PHP中的对象复制与克隆
Posted
技术标签:
【中文标题】PHP中的对象复制与克隆【英文标题】:Object copy versus clone in PHP 【发布时间】:2011-10-21 19:39:54 【问题描述】:考虑以下几点:
$object1 = new stdClass();
$object2 = $object1;
$object3 = clone $object1;
$object1->content = 'Ciao';
var_dump($object1);
// Outputs object(stdClass)#1 (1) ["content"]=> string(4) "Ciao"
var_dump($object2);
// Outputs object(stdClass)#1 (1) ["content"]=> string(4) "Ciao"
var_dump($object3);
// Outputs object(stdClass)#2 (0)
$object2
的内容与$object1
相同是正常的 php 行为吗?
在我看来,$object2
是对 $object1
的引用,而不是副本。
在更改内容之前克隆对象确实像副本一样。
这种行为与变量发生的行为不同,对我来说似乎不直观。
【问题讨论】:
这只是由于缺少规范而导致的另一个 PHP-WTF。 你能详细说明为什么这对你来说不直观吗? 这对我来说很不直观,因为逻辑会随着变量的类型而变化。正如以下答案中所解释的,例如,它不会以数组的方式运行。 在我看来,它是相当不直观,因为$obj2 = $obj1
和$obj2 =& $obj1
做同样的事情。
@Antti29 - 他们做的事情并不完全相同。 $obj2 = $obj1
导致对同一底层对象的 2 个单独引用。因此,如果您随后执行$obj2 = $obj3
,则您的$obj1
变量不受影响。但是,如果您从 $obj2 =& $obj1
开始,您最终会得到 2 个共享相同引用的变量!如果您然后执行$obj2 = $obj3
,您会发现$obj1
现在也指向$obj3
!
【参考方案1】:
是的,这很正常。在 PHP5 中,对象总是通过引用“分配”。要实际复制一个对象,您需要clone
它。
为了更正确,让我引用the manual:
从 PHP5 开始,对象变量不再包含对象本身作为值。它只包含一个对象标识符,允许对象访问者找到实际对象。当一个对象通过参数发送、返回或分配给另一个变量时,不同的变量不是别名:它们持有标识符的副本,它指向同一个对象。
【讨论】:
【参考方案2】:这很正常,我不会认为这是不直观的(对于对象实例):
$object1 = new stdClass();
为$object1
分配一个新的对象实例。
$object2 = $object1;
将对象实例分配给$object2
。
$object3 = clone $object1;
将从现有对象实例克隆的新对象实例分配给$object3
。
如果不是这样,每次你需要传递一个具体的对象实例时,你都需要通过引用传递它。至少这很麻烦,但 PHP 在版本 4 中这样做了(比较 zend.ze1_compatibility_mode
core )。那没用。
Cloning allows the object to specify how it get's copied.
【讨论】:
@stereofrog:从面向对象的角度来看,它不是。然而,PHP实际上 也制作了一个副本,即对象标识符的副本。自 PHP 5 起,对象值只能通过标识符获得,所以实际上,即使使用“我期望一个副本”,这也很直观:您将获得对象标识符的副本。然而,关键点可能是了解如何在 PHP 中实现 OO。 @stereofrog:当对象每次经过某个地方时都会克隆自己时,这会更加令人困惑。当一只狗穿过一扇门时,你也永远不会看到它分裂成两个相同的副本(其中一只狗总是呆在外面......)。另一方面,当我给某人我的电话号码(一个值/原始类型)并且他写下来时,他只有一个副本,而不是号码本身。将原始类型和对象的行为相互比较是没有用的。 @stereofrog:为什么? 是正确的问题。为了更好地说明原因,OP应该更多地分享对他来说不直观的东西。否则很难回答。其次,就语言而言,分配和复制(写入时)可能有所不同。这可能会让人了解语言的工作原理,并促进理解将语言用作工具,而不是对它寄予期望。【参考方案3】:对象复制与对象克隆
class test
public $name;
public $addr;
// i create a object $ob
$ob=new test();
// object copy
$ob2=$ob;
// in object copy both object will represent same memory address
// example
$ob->name='pankaj raghuwanshi';
// i am printing second object
echo $ob2->name;
// output is : pankaj raghuwanshi
// another example
$ob2->name='raghuwanshi pankaj';
echo $ob->name;
// output is : raghuwanshi pankaj
// it means in copy of object original and copy object share same memory place
现在克隆一个对象
$ob1=clone $ob;
echo $ob1->name; // output is : raghuwanshi pankaj
echo $ob->name; // output is : raghuwanshi pankaj
$ob1->name='PHP Clone';
$ob->name='PHP Obj';
echo $ob1->name; // output is : PHP Clone
echo $ob->name; // output is : PHP Obj
// on the base of these output we can say both object have their own memory space
// both are independent
【讨论】:
这个答案是正确的例子【参考方案4】:php5 中的对象本质上是指针,即一个对象变量只包含位于其他地方的对象数据的地址。分配$obj1 = $obj2
仅复制此地址,不会触及数据本身。这可能看起来确实违反直觉,但实际上它非常实用,因为您很少需要对象的两个副本。我希望 php 数组使用相同的语义。
【讨论】:
有些函数当然只接受原生数组。$result = new ArrayObject(array_map($cb, $arrOb->getArrayCopy()));
以上是关于PHP中的对象复制与克隆的主要内容,如果未能解决你的问题,请参考以下文章