PHP – Deep Clone an Object
Cloning an object in PHP is advantageous at times when you want to make a copy of an object so you can alter the copied object’s properties without affecting the original object’s properties.
Reading the docs on php.net, cloning an object is pretty straight forward:
class Car
{
public $type;
public $color;
}
$myCar = new Car();
$myCar->type = 'sports';
$myCar->color = 'red';
$herCar = clone $myCar;
$herCar->color = 'pink;
var_dump('My car | style: ' . $myCar->style . ' | color: ' . $myCar->color);
// Outputs string(35) "My car | style: sports | color: red"
var_dump('Her car | style: ' . $herCar->style . ' | color: ' . $herCar->color);
// Outputs string(37) "Her car | style: sports | color: pink"
// Notice her style is same as mine, but her color is different
Pretty straight forward right? I was able to instantiate an object, set style and color member vars, then clone $myCar object, then set a different value for color member var on cloned object.
As php mentions, references to first level values are maintained, but what about if your object returns another object? Consider the following code:
<pre><?php
class Car
{
public $style;
public $color;
protected $tire;
public function getTire()
{
if (!($this->tire instanceof Tire)) {
$this->tire = new Tire();
}
return $this->tire;
}
}
class Tire
{
public $size;
public $rating;
}
$myCar = new Car();
$myCar->style = 'sports';
$myCar->color = 'red';
$myCar->getTire()->size = '20';
$myCar->getTire()->rating = 'Z';
$herCar = clone $myCar;
$herCar->color = 'pink';
$herCar->getTire()->size = '18';
$herCar->getTire()->rating = 'R';
var_dump('My car | style: ' . $myCar->style . ' | color: ' . $myCar->color);
// Outputs same as above
var_dump('Her car | style: ' . $herCar->style . ' | color: ' . $herCar->color);
// Outputs same as above
var_dump('My car tires | size: ' . $myCar->getTire()->size . ' | rating: ' . $myCar->getTire()->rating);
// Outputs string(35) "My car tires | size: 18 | rating: R"
// Notice that my tire settings were over-ridden by her tire settings
var_dump('Her car tires | size: ' . $herCar->getTire()->size . ' | rating: ' . $herCar->getTire()->rating);
// Outputs string(36) "Her car tires | size: 18 | rating: R"
// This is what we expected
As you can see in the above example, any ‘nested’ objects are ignored via the clone call. Thanks to Wayne Haffenden, there is a way to resolve this situation, you can view his blog post @ http://www.waynehaffenden.com/Blog/PHP-Deep-Object-Cloning. He came up with a clever way of ensuring that any nested objects are also cloned by serializing the object then unserializing upon return. Consider the following code:
class Object
{
// Can't call it clone b/c it's a reserved word
public static function cloneIt($object)
{
return (is_object($object)) ? unserialize(serialize($object)) : null;
}
}
// Instead of making call to php clone, make call to new class::clone
$herCar = Object::cloneIt($myCar);
After adding the code to the original script, when you rerun it you get the following output:
string(35) "My car | style: sports | color: red" string(37) "Her car | style: sports | color: pink" string(35) "My car tires | size: 20 | rating: Z" // Eureka! string(36) "Her car tires | size: 18 | rating: R"
As you can see from the output, we were able to maintain our original tire settings which demonstrates that we were able to perform a ‘deep’ clone where nested objects are cloned as well.
Thanks to Wayne for posting his findings, and I hth.

