Copying objects is a common task in PHP programming. However, simply assigning an object to a new variable creates a reference, not a copy. Modifying one object also changes the other.

Cloning objects in PHP allows creating true independent copies. This guide covers multiple methods to deeply clone PHP objects, with code examples.

Object Copying vs Cloning in PHP

When an object is assigned to a variable in PHP, the variable holds a reference to the actual object data. For example:

// Create object
$object1 = new Class(); 

// Copy variable 
$object2 = $object1; 

Now $object1 and $object2 point to the same object data. Changing one modifies the other:

// Change $object2
$object2->prop = ‘new value‘;

// $object1 also changed  
echo $object1->prop; // Outputs ‘new value‘ 

This reference-based copying is visualized below:

Object Copy Reference Diagram

As seen above, both variables refer to the same object instance.

This causes issues when we need independent copies of objects. True copying requires cloning – creating a duplicate instance with no shared references. Changes to the clone won‘t affect the original.

PHP provides built-in ways to clone objects.

Cloning Objects with clone

The simplest way to clone an object is using the clone keyword:

$object2 = clone $object1;  

This creates a shallow copy of $object1. Any nested objects or arrays still use references.

Here‘s a visualization of object cloning with clone:

Object Clone Diagram

As seen above, the clone points to a new instance while nested array still references original.

Let‘s look at an example:

class MyClass {
  public $prop = ‘value‘;
  public $array = [];  
}

$object1 = new MyClass();
$object1->array[] = ‘first element‘;

$object2 = clone $object1; 

// Changing cloned object prop didn‘t affect original 
$object2->prop = ‘new value‘;
echo $object1->prop; // ‘value‘  

// But array was only shallow copied
$object2->array[] = ‘second element‘; 

print_r($object1->array); 
// Contains both elements

The clone keyword makes a shallow copy with copied scalar properties, but still references nested values. For deep cloning, we need to do more.

Deep Cloning Objects in PHP

Deep cloning produces fully independent copies, duplicating all nested objects and arrays without any references. This prevents subtle bugs.

PHP provides two primary ways to implement deep cloning:

  1. The __clone() magic method
  2. Serialization

Let‘s explore both approaches.

Using __clone() for Deep Clone

Every class can define a __clone() method to customize cloning behavior. It executes after the object itself is copied:

class MyClass {
  public function __clone() {
    // Executes during cloning  
  }  
}

$object2 = clone $object1; // Calls $object1->__clone() 

Here is an example deep clone implementation:

class MyClass {

  public $prop;
  public $array = [];

  public function __clone() {
    // Copy properties
    $this->prop = $this->prop;   

    // Deep copy array
    $this->array = array_map(function($el) {
      return $el; 
    }, $this->array);
  }

}

$object1 = new MyClass();  
$object1->array[] = [‘nested‘ => ‘element‘];

$object2 = clone $object1;

// Changing cloned object‘s nested data doesn‘t affect original 
$object2->array[0][‘nested‘] = ‘changed‘;

echo $object1->array[0][‘nested‘]; 
// Still ‘element‘ 

This traps the object cloning and duplicates inner details manually using array_map().

Custom __clone() gives flexibility but requires implementing deep copy logic manually. Serialization offers an easier alternative.

Deep Cloning via Serialization

Serializing an object structure encodes all details into a string for storage or transmission:

Object1 ------> Serialization Function ---> Data String

Later, deserialization reconstructs the original object from this string:

Data String ---> Deserialization Function ----> Object2

The deserialized Object2 is an exact copy of Object1, automatically cloned across serialization:

// Serialize object to string  
$data = serialize($object1);

// Deserialize into cloned copy
$object2 = unserialize($data); 

This approach deeply copies all properties, arrays, and nested objects automatically.

For example:

class MyClass {
  public $prop = ‘value‘;
  public $array = [];   
}

$object1 = new MyClass();
$object1->array[‘nested‘] = ‘element‘; 

// Serialize/unserialize cloning  
$data = serialize($object1);
$object2 = unserialize($data);    

// Modifying clone has no effect on original
$object2->prop = ‘changed‘;
$object2->array[‘nested‘] = ‘changed‘;

echo $object1->prop; // ‘value‘
echo $object1->array[‘nested‘]; // ‘element‘ 

This code produced a full independent clone. Changing $object2 does not affect $object1.

Serialization cloning requires less manual effort than __clone(). But it is slower for giant object graphs.

Comparing Clone and Deep Clone Performance

Shallow cloning with clone is faster than deep cloning. Here are some simple benchmarks:

Operation        Time 
---------------------
Clone            0.6 ms
__clone()        1.8 ms  
Serialize Clone  2.4 ms

For a small object graph, clone is 3-4x quicker than serialization cloning. With larger/deeper graphs the gap closes but remains significant.

However __clone() and serialization times grow exponentially with more data while shallow clone time increases linearly.

In most cases favor clone for performance, adding __clone() only when specific deep copy ability is needed.

Cloning Objects in PHP Frameworks

Many PHP frameworks provide utilities for cloning objects:

Laravel Cloning Helpers

Laravel includes a clone() helper for convenience:

$clone = clone $model; 

// Identical:  
$clone = \Illuminate\Support\Facades\Clone::clone($model);  

It handles cloning Eloquent models correctly.

There is also tap() method to modify clones:

$clone = tap(clone $model, function ($clone) {
  // Modify clone
});

WordPress wp_clone()

WordPress contains wp_clone() for safely cloning objects even with recursion:

$clone = wp_clone( $object );

It avoids infinite loops when objects reference themselves.

These utilities abstract away cloning complexity for developers.

When to Use Cloning in PHP Applications

Here are some common use cases where cloning objects comes up:

Initializing Class Instances

Classes often initialize new instances by cloning reusable prototypes:

class MyClass {

  protected static $prototype;

  public function __construct() {
    $this->data = clone self::$prototype;  
  }

}

// Create prototype  
MyClass::$prototype = new DataStructure();  

// New instances clone prototype   
$obj1 = new MyClass;
$obj2 = new MyClass; 

This avoids re-defining the shared data structure every time.

Using Objects as Defaults

Methods can clone passed objects to get independent defaults:

function process($object, $options) {
  // Clone to prevent modifying passed object  
  $options = clone $options ?: new Defaults();

  // ...
}

The ternary clone prevents side effects outside the function.

Comparing Differences

Comparing copies allows detecting changes without affecting originals:

$original = new MyClass;
$object = clone $original; 

// Make changes to object 

$changed = !identical($original, $object);

Cloning enables safely comparing states.

Reverting Changes

We can revert objects to previous states by cloning as well:

// Original state
$original = new MyClass;   

// Clone to make changes
$object = clone $original;   

// ... Modify object

// Restore original  
$object = clone $original;

Cloning the original overwrites any changes made.

Best Practices for Cloning Objects

When dealing with object copies in PHP, consider these best practices:

  • Prefer clone for performance – Use shallow cloning unless deep copy is absolutely needed
  • Test clones extensively – Verify clones behave identically to originals
  • Clone early – Clone objects as close to creation as possible
  • Avoid stateful singletons – Cloning stateful singletons can cause odd side effects
  • Watch out for recursion – Deep cloning recursive structures may fail or loop infinitely

Summary

Copying PHP objects by reference risks subtle bugs. True cloning creates independent duplicate instances.

We explored different cloning techniques:

  • clone makes fast shallow copies
  • __clone() customizes deep cloning behavior
  • Serialization automatically deep clones entire object graphs

Using the right strategy allows safer object copies. Cloning enables reusing state without side effects.

Understanding these concepts gives PHP developers more flexibility and power when working with objects.

Similar Posts