Categories
PHP

Object Cloning

How to use the clone keyword to clone an object and use the __clone magic method to customize the behavior of the cloning process.

When you assign an object from one variable to another, you do not copy it, but merely assign a handle or reference to it.

<?php
 class XYZ {
  public $var = 0;
  public $abc = 'ABC';
 }

 $a = new XYZ();
 $b = $a;
 $b->var = 2;

 echo $a->var; # Prints 2, expecting 0
 echo $b->var; # Prints 2
 # $a and $b point to the same underlying instance of XYZ

However, situations will arise where you’ll actually want to assign a full copy of an existing object to a new variable. This is known as cloning, and is done via the clone operator.

<?php
 $a = new XYZ();
 $b = clone $a;
 // $b now is a NEW object with all the member variables set
 // to the values they had in $a
 
 $b->var = 2;
 echo $a->var; # Prints 0, as expected
 echo $b->var; # Prints 2

When you clone an object in PHP, the language creates a new instance of the class and assigns copies of the corresponding variables in the original instance to this new object’s member variables by default. However, this is a shallow copy, meaning that if one of those member variables is itself a reference to an object, only that reference is copied.

__clone function

If the default behavior for cloning is not sufficient for your needs, you can implement the __clone function in your class, which PHP calls after it has performed the shallow copy of the member variables.

Remember example in the Static Variables and Methods tutorial, we used a static variable to count the number of instances of a class that have been created:

 class User {
  private static $x = 0;
  public function __construct () {
   self::$x++;
   echo 'Instances created: '. self::$x .'<br>';
  }
 }
 $a = new User(); # Prints: Instances created: 1
 $b = clone $a; # Prints nothing

In the above code, the increment was performed in the constructor and when you clone an object the User class does not count the cloned object. To solve this, we use __clone method in the User class:

<?php
 class User {
  private static $x = 0;
  public function __construct () {
   self::$x++;
   echo 'Instances created: '. self::$x .'<br>';
  }
  function __clone() {
   self::$x++;
   echo 'Instances created: '. self::$x .'<br>';
  }
 }
 $a = new User(); # Instances created: 1
 $b = clone $a;   # Instances created: 2

Now, whenever the object is cloned, the __clone method is called and the cloned instance is also counted.

The __clone() method does not override the cloning process, it just allows you to amend the wrongdoing, where you might not normally be satisfied with the outcome.


PHP OOP Tutorials: