PHP克隆儿童
我有一个对象,它是一个基本的树。我需要对它进行深度复制,并发现自己实现了克隆方法。成功的代码是:PHP克隆儿童,php,clone,Php,Clone,我有一个对象,它是一个基本的树。我需要对它进行深度复制,并发现自己实现了克隆方法。成功的代码是: function __clone() { $object = new CustomXML($this->rootElement); foreach ($this->elements as $key => $element) { $this->elements[$key] = clone $this->elements[$key];
function __clone() {
$object = new CustomXML($this->rootElement);
foreach ($this->elements as $key => $element) {
$this->elements[$key] = clone $this->elements[$key];
$object->elements[$key] = $this->elements[$key];
}
$object->attributes = $this->attributes;
$object->value = $this->value;
$object->allowHTML = $this->allowHTML;
$object->endTag = $this->endTag;
$object->styles = $this->styles;
$object->childID = $this->childID;
return $object;
}
我的问题是。。。为什么我必须使用
$this->elements[$key] = clone $this->elements[$key];
$object->elements[$key] = $this->elements[$key];
为什么我不能用它呢
$object->elements[$key] = clone $this->elements[$key];
使用第二个仍然会留下对孩子们的引用。为什么会这样?$this->elements中的值属于同一类。经过长时间的检查,我创建了一个测试场景,并意识到我根本不理解克隆方法 考虑以下示例代码:
<?php
class A {
function __construct($value = "1") {
$this->value = $value;
$this->children = array();
}
function addChild() {
$this->children[] = new A(count($this->children));
}
function __clone() {
foreach ($this->children as $key => $child) {
$this->children[$key] = clone $this->children[$key];
//$object->children[$key] = clone $this->children[$key];
}
}
}
$a = new A();
$a->addChild();
$b = clone $a;
var_dump($b);
$b->value = "test";
$b->children[0]->value = "test2";
var_dump($a);
var_dump($b);
您可以说调用$b=clone$a代码>相当于执行以下操作:
$b = $a;
$b->__clone();
\uuu clone()
在已创建的对象浅拷贝上调用
PHP将浅层复制所有属性并创建一个新对象,而无需调用其构造函数(类似于序列化和反序列化)。然后PHP调用新对象上的\uuu clone()
,以便您可以根据自己的喜好修改它。因为它修改了对象,所以不应该返回任何内容
您的代码(如果您总是需要深度副本)应如下所示:
foreach ($this->elements as $key => $element) {
$this->elements[$key] = clone $this->elements[$key];
}
function __clone() {
foreach ($this->children as $key => $child) {
$this->children[$key] = clone $this->children[$key];
}
}
但是,我强烈建议您不要这样做!不要依赖于clone
关键字,而是添加显式返回克隆对象的方法(例如,这将使您可以控制副本是浅拷贝还是深拷贝。如果仅使用clone
,则无法控制此操作
以下是一个例子:
interface DeepCopyable
{
/**
* Return a copy of the current object
*
* @param $deep bool If TRUE, return a deep copy
* @return object
*/
public function copy($deep=false);
}
class TreeNode implements DeepCopyable
{
private $I_AM_A_CLONE = false;
protected $children = array();
function __clone() {
$this->I_AM_A_CLONE = true;
}
public function addChild(Copyable $child) {
$this->children[] = $child;
}
public function copy($deep=false) {
$copy = clone $this;
if ($deep) {
foreach ($this->children as $n => $child) {
$copy->children[$n] = $child->copy($deep);
}
}
return $copy;
}
}
$a = new TreeNode();
$a->addChild(new TreeNode());
var_dump($a);
var_dump($a->copy());
var_dump($a->copy(true));
此示例还说明了如何正确使用\uuuu clone()
。当克隆对象的私有或受保护属性不应与原始属性相同时,您需要添加克隆魔法方法。例如,如果对象上的id
属性应该是唯一的,您可能希望确保克隆不会具有相同的id,并且永远不希望调用code来控制它,或者“脏”标志,或者其他什么