0

这是一个简化的代码:

Class Bar
{
    static $foo;

    public function __construct(Foo $foo)
    {
        $this->foo = $foo;
        $this->loop($foo,1);
    }

    public function loop(Foo $foo, $index)
    {   

        $a = $foo->a;
        if ($index < 3)
        {
            $a[$index]->var2 += $a[$index]->var1;
            $a[$index]->var1 = 0;
            $foo->dump();
            $this->foo->dump();

            $this->loop(new Foo($a),++$index);
        }
    }
}

$p = array(
      new Baz(100,200),
      new Baz(300,400),
      new Baz(400,200),
      new Baz(600,400)
    );

new Bar(new Foo($p));

这段代码有两个问题。也许更多;)

  1. 看起来 var1 的重新分配对 $foo 有影响。我希望在我将 $foo->a 传递给 $a 之后它没有。

  2. 在构造中,我将 $foo 分配给 $this->foo 但是在每个循环之后它都会改变它的值。有人能指出 $this->foo 的值在哪里变化吗?

Foo 类的更多信息定义

Class Foo
{
    public $a;
    public function __construct($a)
    {
        $this->a = $a;
    }
    public function dump($title="")
    {
        echo "<br/>================".$title."=============================";
        echo "<table>";
        for ($i=0; $i<sizeof($this->a); $i++)
        {
            echo "<tr>";
            echo "<td>" . $this->a[$i]->var1 . "</td>";
            echo "<td>" . $this->a[$i]->var2 . "</td>";
            echo "</tr>";

        }
        echo "</table>";
    }

}

巴兹班

Class Baz
{
    public $var1;
    public $var2;
    public function __construct($var1, $var2)
    {
        $this->var1=$var1;
        $this->var2=$var2;
    }

}

转储结果:

================IM foo dump=============================
100 200
0   700
400 200
600 400

================Im $this->foo dump=====================
100 200
0   700
400 200
600 400

================IM foo dump=============================
100 200
0   700
0   600
600 400

================Im $this->foo dump======================
100 200
0   700
0   600
600 400
4

1 回答 1

1

您看到的行为是正常的。在 PHP 中将对象分配给变量时,传递的是引用,而不是值;如果您想拥有副本而不是引用,则必须创建一个 clone

例如,在以下场景中:

$blub = new Bar();
$a = $blub;
$b = $blub;
$c = $blub;

$a, $b, $c 可以说只是“别名”,指向 $blub; 这意味着设置 $a 的任何成员对 $blub 有直接影响,因此对 $b 和 $c 也有影响。

但是,通过使用关键字克隆,您可以获得您正在寻找的结果:

$blub = new Bar();
$a = clone $blub;
$b = clone $blub;
$c = clone $blub;

这里我们显式地创建了独立的副本,因此修改 $a 的内容不会改变 $blub、$b 或 $c。

最后,这是您的示例类如何实现克隆以处理独立对象的样子:

Class Bar
{
    public $foo;

    public function __construct(Foo $foo)
    {
        $this->foo = $foo;
        $this->loop(clone $foo, 1);
    }

    public function loop(Foo $foo, $index)
    {   
        $a = array();

        foreach($foo->a as $key => $subobject) {
            $a[$key] = clone $subobject;
        }

        if ($index < 3)
        {
            $a[$index]->var2 += $a[$index]->var1;
            $a[$index]->var1 = 0;
            $foo->dump();
            $this->foo->dump();

            $this->loop(new Foo($foo->a),++$index);
        }
    }
}


new Bar(new Foo($p));

更新

由于传递了一个对象数组,因此仅仅克隆 $foo 是不够的:

$p = array(
      new Baz(100,200),
      new Baz(300,400),
      new Baz(400,200),
      new Baz(600,400)
    );

即使您克隆了托管数组的对象,数组中的对象本身仍然指向相同的对象,因为数组只是保存引用;克隆对象时,会复制数组成员及其内容,包括引用。理解引用和值的概念需要一点时间,但最终你会发现一切都像一个谜题:)

无论如何,在这种特定情况下,必须先克隆数组中的对象,然后再使用它们,这可以通过 Bar::loop 函数中的以下循环轻松实现:

        foreach($a as $key => $subobject) {
            $a[$key] = clone $subobject;
        }

请参阅上面的课程以获取完整的编辑。

于 2012-07-02T23:22:00.887 回答