How To Clone Objects in PHP5

      No Comments on How To Clone Objects in PHP5

Object cloning in PHP puts the same problems as in any other language. In addition to other popular languanges in PHP, starting with PHP5 there is present the operator clone. By default it creates an identical clone of the original object. If the original object contains references to another object, the cloned object will contain references to the same object. For example and object Student has a reference to an object of type Classroom. If we shallow clone it the student clone will contain a reference to the same Class:

$student_clone = clone $student_original;


Let’s consider the following case. We have an object of type Car which keeps a reference to an object of class Engine. If we clone it using the standard way the $cloned_car will have the same reference to the $engine as the $original_car. That’s awkward. Two cars having the same engine. For such cases we should use a deep cloning instead of a shallow cloning. That means we should clone the engine as well and all of its own components when we clone the car.

To do that we should implement a __clone method in the Car class. The __clone method is reserved and can not be cloned directly. When an object is cloned after the default cloning operations are finished the __clone method is invoked if it’s available. There we should implement what operations we need.

class Engine
{
	public $type;
}		

class Car
{
	public $wheelCount; // this is a variable not a reference
	public $engine; // this is a reference
	
	function __clone()
	{
		$this->engine = clone $this->engine;
	}
}
 
$original_car = new Car();
$original_car->wheelCount = 4;
$original_car->engine = new Engine();
$original_car->engine->type = 'small engine';

$cloned_car = clone $original_car;
$cloned_car ->engine->type = 'big engine';

var_dump($original_car);
var_dump($cloned_car);

.. and this is the result:

object(Car)#1 (2) {
  ["wheelCount"]=>  int(4)
  ["engine"]=>  object(Engine)#2 (1) {
    ["type"]=>    string(12) "small engine"
  }
}
object(Car)#3 (2) {
  ["wheelCount"]=>  int(4)
  ["engine"]=>  object(Engine)#4 (1) {
    ["type"]=>    string(10) "big engine"
  }
}

If we remove the __clone method we’ll obtain the following result. Please note that both $original_car and $cloned_car have the same “big engine” because when we modify $cloned_car ->engine->type we change the same engine object that is used by $original_car as well:

object(Car)#1 (2) {
  ["wheelCount"]=>
  int(4)
  ["engine"]=>
  object(Engine)#2 (1) {
    ["type"]=>
    string(10) "big engine"
  }
}
object(Car)#3 (2) {
  ["wheelCount"]=>
  int(4)
  ["engine"]=>
  object(Engine)#2 (1) {
    ["type"]=>
    string(10) "big engine"
  }
}

Leave a Reply

Your email address will not be published. Required fields are marked *