具有对象属性数组的深层复制对象 - 如何或替代?

时间:2016-04-07 16:37:03

标签: php

这将是一个难以解释的问题。

我有一个相当复杂的类树,我试着简化:

class Tree {

    /**
     * @var Node[]
     */
    private $nodes;

    /**
     * @var Edge[]
     */
    private $edges;

}

class Node {


    /**
     * @var Value[]
     */
    private $values;

    /**
     * @var array
     */
    private $someArray;

}

class Value {

    /**
     * @var float
     */
    private $result;

}

所以你可以看到我有一个对象树包含两个对象数组(节点和边缘),每个节点都有一个< strong>对象数组(值),其他一些“简单数组”和每个都有属性结果

要计算属性结果,我基本上需要在我的树上运行等...所以有些业务逻辑最终仍然在同一个树中,但我的节点有一些计算结果。

所以我到目前为止做的是:

$tree = myCalculationFunction($tree, $calcParameter);

return $tree->getNode(1)->getValue(1)->getResult();

但是当我使用不同的calcParameter另外调用相同的函数时,当然我的Tree操作引用的节点,值等。

所以我不能:

$initialTree = myCalculationFunction($tree, $calcParameter);

$treeOne = myCalculationFunction($initialTree, $calcParameterOne);
$treeTwo = myCalculationFunction($initialTree, $calcParameterTwo);

$result1 = $treeOne->getNode(1)->getValue(1)->getResult();
$result2 = $treeTwo->getNode(1)->getValue(1)->getResult();

所以我没有$ initialTree的深层副本,因为其中的所有对象都是byReference。我无法克隆,我也看不到像here这样的手动/自定义深层复制如何适用于此案例。

我怎样才能实现这一目标?我基本上需要initialTree稳定,每个计算函数调用都会操作最初“计算树”的完整副本。

1 个答案:

答案 0 :(得分:3)

您可以从this问题扩展该方法,并为每个类实现自定义__clone方法。由于节点或边缘本身之间似乎没有任何关系,因此应该足以完成您想要的任务。

值得一提的是,正如documentation中所述,在克隆后立即在新对象上调用__clone。它实际上并不负责克隆最初可能看似合乎逻辑的对象。

因此,简化了TreeNode类:

class Tree
{
    private $nodes;

    private $edges;

    public function __clone()
    {
        $this->nodes = array_map(function ($node) {
            return clone $node;
        }, $this->nodes);

        $this->edges = array_map(function ($edge) {
            return clone $edge;
        }, $this->edges);

        // clone other properties as necessary
    }
}

class Node
{
    private $values;

    private $someArray;

    public function __clone()
    {
        $this->values = array_map(function ($value) {
            return clone $value;
        }, $this->values);

        $this->someArray = array_map(function ($elem) {
            return clone $elem;
        }, $this->someArray);

        // clone other properties as necessary
    }
}

只需按照此模式为每个课程进行操作,它将以递归方式深度克隆整个树。