使用对象属性数组深度复制对象-如何或替代


Deep-copy Object with Array of Object Properties - how to or alternative?

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

我有一个相当复杂的类Tree,我试图简化:

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

因此,您可以看到,我有一个对象树,其中再次包含两个对象数组(节点和边)并且每个节点都有一个对象数组(值)有一个属性结果。

为了计算属性结果,我基本上需要在树上来回运行等等……所以有些人有业务逻辑,最终会在同一个树中,但我的节点有一些计算结果。

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

$tree = myCalculationFunction($tree, $calcParameter);
return $tree->getNode(1)->getValue(1)->getResult();

但是没有,当我用不同的calcParameter额外调用相同的函数时,当然我的树在引用的节点、值等上操作。

所以我不能:

$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。我无法克隆,也看不出像这里这样的手动/自定义深度复制将如何适用于这种情况。

我如何在这里实现这一点?我基本上需要initialTree是稳定的,并且每个计算函数调用都操纵最初"计算树"的完整副本。

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

值得一提的是,正如文档中所描述的,__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
    }
}

只需为以后的每个类遵循这个模式,它就会递归地深度克隆整个树。