Search code examples
phpclone

Clone object with sub-objects in PHP


I have an object (called a) which contains an array of two other objects (called b). I am trying to clone that object (a). When i clone the object, i also want to clone the other two objects. However, when i run a code to change the sub-objects(b) in the original object(a) array, it also changes the array with objects(b) in the cloned object(a). How do i prevent this? This is my code:

<?php
class a{
    public $b = array();

    function __clone(){
        foreach($this->b AS $key => $b){
            $this->b[$key]  = clone $b;
        }   
    }

    function addB($name,$b){
        $b->setA($this);
        $this->b[$name] = $b;
    }


}

class b{
    public $a;
    public $var = 'no';
    function execute(){
        $this->var  = 'yes';
    }

    function seeB1(){
        return $this->a->b['b1']->var;
    }

    function setA($a){
        $this->a    = $a;
    }
}



$a1 = new a;
$b1 = new b;
$b2 = new b;

$a1->addB('b1',$b1);
$a1->addB('b2',$b2);


//Clones A
$a2 = clone $a1;


$a1->b['b1']->execute();

var_dump($a1->b['b2']->seeB1()); //This should say Yes. It does
var_dump($a2->b['b2']->seeB1()); //This should say No. It says Yes

?>

The output is:

string 'yes' (length=3)

string 'yes' (length=3)

What i want to do with this script is clone A. After i clone A, i run the function execute() of the original b1 to change $var. Then I view original b1 from the original b2. This shows that $var of original b1 has changed, as it should be. However, if I view cloned b1 from cloned b1, it also shows that $var has changed. It shouldnt.

What am i doing wrong?

Regards, Tom.


Solution

  • You can try to replace your __clone function with the following:

    function __clone() {
        foreach ($this as $key => $value) {
            if (is_object($value) || (is_array($value))) {
                $this->{$key} = unserialize(serialize($value));
            }
        }
    }
    

    By using the serialize/unserialize method you will definitely avoid changing the original properties of the object.

    Tested it and it works fine for simple objects like the ones in your example.