In our advanced PHP training course we cover object orientation and how it is implemented in PHP. PHP uses the terminology "magic methods" to refer to class methods that other object orientated languages, such as Java, would refer to either as standard class functionality, like constructors, or methods that form part of the base class from which all other classes derive, i.e. the Object class in Java. In PHP magic methods include such class functions as __toString and __clone.

PHP Object Cloning

Understanding the need for object cloning may be a little difficult at first for a procedural programmer to understand, especially one coming from a PHP background. When variables are assigned in PHP by default it is done via a pass-by-value mechanism. I.E. the variable is given a copy of the "contents" of the expressions which it is assigned. Hence if a variable is assigned the contents of another variable, changing the 2nd variables value does not affect the first variable.

$a=10;

$b=$a;

$b+=10;

echo $a."

\r";

echo $b;

The output of the above is:

10

20

From the above it is clear that variable $b got a copy of the content of $a and then performs operation on its own copy of the content. i.e. $b and $a do not point to the same content.

PHP Object Assignment

When it comes to assigning variables the result of an object creation operation the variable receives a copy of the "pointer" to the object. ("Pointer" should not be confused with C pointers, although I find thinking of them as pointing to the same location in memory as handy. Another way to think of this is as an alias to the same object or value.). This is different to what happens for variables that are assigned simple values. So if the second variable changes state of the object it references, all variables "pointing" to that object will access the updated state.

Of course this is natural and what one would expect to have happen. Its so natural that many do not fully comprehend this until they need to make a "copy" of an existing object.

class Person { public $firstName; public $lastName; } $person1 = new Person(); $person1->firstName="First Name"; $person1->lastName="Last Name"; $person2 = $person1; $person2->firstName="Surprise"; var_dump($person1); var_dump($person2);

Output

object(Person)#1 (2) { ["firstName"]=> string(8) "Surprise" ["lastName"]=> string(9) "Last Name" } object(Person)#1 (2) { ["firstName"]=> string(8) "Surprise" ["lastName"]=> string(9) "Last Name" }

From the above it can be seen that both variables "point" to the same object. So what happens when you want a copy of an object and not just a copy of the reference to the object? This is where the clone keyword comes in. To create a copy of an object one needs to do the following:

$person3 = clone $person1; $person3->firstName="Total Recall"; var_dump($person1); var_dump($person3);

Output

object(Person)#1 (2) { ["firstName"]=> string(8) "Surprise" ["lastName"]=> string(9) "Last Name" } object(Person)#2 (2) { ["firstName"]=> string(12) "Total Recall" ["lastName"]=> string(9) "Last Name" }

So the clone keyword creates an independent copy of the target object. But there is a problem with the cloning process.

PHP Clone Shallow Copy Problem

When the clone process runs it creates a shallow copy of the target object. What this means is that all non-object types get their values copied to the member variables of the new object but any variables referencing object simply get the object reference ("pointer") copied. So both object end up pointing to the same objects. The code below illustrates this a bit more clearly.

class Person { public $firstName; public $lastName; public $company; } class Company { public $companyName; } $companyA = new Company(); $companyA->companyName="PHP Training Co"; $person1 = new Person(); $person1->firstName="First Name"; $person1->lastName="Last Name"; $person1->company= $companyA; $person3 = clone $person1; $person3->firstName="Total Recall"; $person3->company->companyName="Awesome Co"; var_dump($person1); var_dump($person3);

Output

object(Person)#2 (3) { ["firstName"]=> string(10) "First Name" ["lastName"]=> string(9) "Last Name" ["company"]=> object(Company)#1 (1) { ["companyName"]=> string(10) "Awesome Co" } } object(Person)#3 (3) { ["firstName"]=> string(12) "Total Recall" ["lastName"]=> string(9) "Last Name" ["company"]=> object(Company)#1 (1) { ["companyName"]=> string(10) "Awesome Co" }

So the above shows that the copy was not perfect. Each copy now refers to the same instance of the company object. This may be what you want but maybe it is not what you want and you want a complete standalone copy of the original object. To do this you need to implement the __clone magic method.

PHP __clone Magic Method - Deep Copy

In the __clone magic method you will need to implement your own copy of the objects you wish to copy. In some cases this may be a more involved process of accessing the original copies member variables and copy those that are required but in this example we can simply use our newly learnt clone keyword to do the dirty work for us.

class Person { public $firstName; public $lastName; public $company; public function __clone(){ $this->company = clone $this->company; } } class Company { public $companyName; } $companyA = new Company(); $companyA->companyName="PHP Training Co"; $person1 = new Person(); $person1->firstName="First Name"; $person1->lastName="Last Name"; $person1->company= $companyA; $person3 = clone $person1; $person3->firstName="Total Recall"; $person3->company->companyName="Awesome Co"; var_dump($person1); var_dump($person3);

Output

object(Person)#2 (3) { ["firstName"]=> string(10) "First Name" ["lastName"]=> string(9) "Last Name" ["company"]=> object(Company)#1 (1) { ["companyName"]=> string(15) "PHP Training Co" } } object(Person)#3 (3) { ["firstName"]=> string(12) "Total Recall" ["lastName"]=> string(9) "Last Name" ["company"]=> object(Company)#4 (1) { ["companyName"]=> string(10) "Awesome Co" }

So the clone magic method allows developers to implement a deep copy of an object when it is cloned. PHP first performs a shallow clone and the calls the clone method on the new object, if it exists, to complete the cloning process. Magic method such as __clone are covered in our advance PHP training course at Jumping Bean.