PHP 问题:对象属性增量
问题
以下代码段打印什么内容,为什么?
value++; } $a = new MyClass(); $a->value = 1; doSomething($a); print $a->value;
回答
你可能认为上面代码的结果是1,但实际产生的值是2。这是因为虽然我们没有特意通过引用传递函数参数,但实际上是因为PHP中的所有对象都是通过引用传递的。
这是PHP的一个非常重要的特性,如果您在设计系统时不牢记它,几乎肯定会导致错误。可能会让您感到困惑的一件事是,即使在分配变量时,PHP对象也是通过引用传递的。以下面的代码片段为例,它是上一个示例的后续内容。
$b = $a; $b->value = 15; echo $a->value;
您可能再次期望此代码的输出为2(从上一个示例开始),但我们真正得到的是15。发生这种情况是因为当您将一个对象分配给另一个变量时,您正在创建对原始对象的引用。因此,当我们尝试更改$b中“value”属性的值时,我们实际上是在更改原始对象中的值。
为了解决这个问题并创建一个单独的对象,我们使用clone关键字。clone关键字将创建对象的浅表副本,该副本不会附加到原始对象。
$b = clone $a; $b->value = 15; echo $a->value;
上面的示例现在按预期打印出2。
在克隆对象方面也有一些问题。请注意,我在介绍该术语时说的是“浅拷贝”。这是因为它会复制原始对象,但不会以相同的方式克隆所有内部对象。以下面的代码示例为例(它不遵循任何先前的示例)。
value = new AnotherClass(); $a->value->something = 5; echo $a->value->something . "\n"; $b = clone $a; $b->value->something = 10; echo $b->value->something . "\n"; echo $a->value->something . "\n";
如您所料,第一个echo调用打印出5,但第二个调用都打印10,因为虽然我们创建了原始对象的副本,但所有内部对象都是通过引用传递的。为了允许以相同的方式复制内部对象,可以使用调用的魔术方法__clone()。每当您克隆对象时都会调用此方法。重写上面的例子,我们可以创建一个新AnotherClass()对象,这样当我们更改对象$a中的值时,对象$b中的值也不会更改。
value = new AnotherClass(); } } class AnotherClass { public $something; } $a = new MyClass(); $a->value = new AnotherClass(); $a->value->something = 5; $b = clone $a; $b->value->something = 10; echo $b->value->something; echo $a->value->something;
上面的例子现在打印10后跟5。当$b中的相同值改变时,内部对象在$a中保存的值的原始值不会改变。
当然,在__clone()调用期间创建另一个对象意味着我们会丢失该对象的所有原始信息。我们可以手动转移这些值,但这是一种无法维护的方法。另一种__clone()方法是通过以下方式克隆方法内部的内部对象。
class MyClass { public $value; public function __clone() { $this->value = clone $this->value; } }
这将创建从原始对象到当前对象的内部对象的副本。