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中的对象复制与克隆的主要内容,如果未能解决你的问题,请参考以下文章

前端学PHP之面向对象系列第五篇——对象操作

java中的浅克隆和深克隆是啥

php对象克隆

java对象复制与克隆

反射实现java深度克隆

JAVA浅复制与深复制