1

That's gonna be a tough one to explain.

I have a class Tree which is rather complex, I try to simplify:

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;

}

So you can see I have an object Tree containing two arrays of Objects again (Node and Edge) and every Node has an array of objects (Value), some other 'simple array' and every Value has a property result.

To calculate the property result I basically need to run up and down my tree etc... so some have business logic which will end up in still the same Tree but having some calculated results for my nodes.

So what I do so far is something like:

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

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

But no when I call additionally the same function with a different calcParameter of course my Tree operates on referenced Nodes, Values etc.

So I cannot:

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

So by I have no deep-copy of my $initialTree because all objects in it are byReference. I cannot clone and I don't see how some manual/custom deep-copy like here will work for this case.

How can I achieve this here? I basically need the initialTree to be stable and every calculation function call manipulates a fully copy of the initially 'calculated tree'.

Community
  • 1
  • 1
LBA
  • 3,859
  • 2
  • 21
  • 60

1 Answers1

3

You could extend the approach from this question, and implement a custom __clone method for each of your classes. Since there don't seem to be any relations between the nodes or edges themselves, it should be enough to accomplish what you want.

It might be worth mentioning that, as described in the documentation, __clone is invoked on the new object just after cloning. It isn't actually responsible for cloning the object which might seem logical at first.

So, simplified for the Tree and Node class:

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

Just follow this pattern for each class down the road and it will recursively deep clone your whole tree.

Community
  • 1
  • 1
Kuba Birecki
  • 2,926
  • 1
  • 13
  • 16
  • Thank you very much - this is what I wanted to avoid :-( I'll let it open shortly to check whether someone has an alternative or any idea. But I am pretty sure I'll have to follow your approach and will accept it then. – LBA Apr 08 '16 at 09:00
  • I also stumbled upon this library which might be what you're looking for: https://github.com/myclabs/DeepCopy . The downside is that it'll add another dependency to your project. – Kuba Birecki Apr 08 '16 at 09:39
  • Thanks - the library is working for me! And as it's just generally following the approach which you suggested in your answer I accept it. – LBA Apr 08 '16 at 10:28