PHP 克隆子代

标签 php clone

我有一个对象,它是一个有点基本的树。我需要对其进行深度复制,并发现自己实现了 __clone 方法。成功的代码为:

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 中的值属于同一类。

最佳答案

__clone() 在对象的已创建的浅拷贝上调用。 See the documentation

PHP 将浅复制所有属性并创建一个新对象,而不调用其构造函数(类似于序列化和反序列化)。然后 PHP 在 new 对象上调用 __clone(),以便您可以根据自己的想法修改它。因为它修改对象,所以它不应该返回任何内容。

您的代码(如果您总是想要深层复制)应如下所示:

   function __clone() {
        foreach ($this->children as $key => $child) {
            $this->children[$key] = clone $this->children[$key];
        }
   }

但是我强烈建议您不要这样做!不要依赖 clone 关键字,而是添加方法来显式返回克隆对象(例如 DOMNode::cloneNode() )。例如,这可以让您控制副本应该是浅的还是深的。如果您只是使用克隆你无法控制它。

这是一个例子:

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));

此示例还说明了__clone()正确使用。 当克隆对象的私有(private)或 protected 属性不应与原始对象相同时,您需要添加克隆魔术方法。例如,如果某个对象有一个应该是唯一的 id 属性,您可能希望确保克隆不会具有相同的 ID,并且您永远不想调用代码来控制它。或者“脏”标志,或者其他什么。

关于PHP 克隆子代,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13883864/

相关文章:

java - 为什么说我们不需要克隆不可变类?

php - MySQL 行(除了最后一行)是缩进的并且不可搜索? (加载数据文件)

php mysql 在 config.php 中获取变量并在另一个 php 文件中使用它 * 新的

php - Symfony/学说 : How to make Doctrine working with Unix socket?

Git 克隆与 Git 创建存储库

.net - SqlCommand.Clone() 是创建深拷贝还是浅拷贝?

php - 物理删除在 laravel5 中启用软删除的模型?

php - 如何创建多重搜索?

JQUERY 跨 div 拖动和克隆

java - Clone() vs Copy constructor - 在java中推荐