Deep Cloning Objects with PHP __clone Method
When cloning an object in PHP using the clone keyword,
PHP performs a shallow copy by default, meaning nested objects remain
referenced to their original instances. This article explains how to
implement a deep clone by overriding the magic __clone()
method to manually clone nested object references, ensuring complete
independence between the original and cloned objects.
Understanding Shallow vs. Deep Cloning
By default, PHP’s clone keyword creates a shallow copy
of an object. While primitive properties (like strings, integers, and
booleans) are copied by value, any properties containing object
references are copied by reference.
If you modify a nested object inside a shallow-cloned object, the change will reflect in the original object because both point to the same instance in memory. To prevent this, you must perform a deep clone.
Implementing the
__clone() Magic Method
PHP provides the __clone() magic method to define how an
object should behave when it is cloned. This method is automatically
called on the newly copied object once the shallow copy is complete.
Within this method, $this refers to the cloned copy, not
the original.
To deep clone nested objects, you must explicitly call
clone on those nested object properties inside the
__clone() method.
Here is a practical example:
class Address {
public string $city;
public function __construct(string $city) {
$this->city = $city;
}
}
class User {
public string $name;
public Address $address;
public function __construct(string $name, Address $address) {
$this->name = $name;
$this->address = $address;
}
// This magic method handles the deep clone
public function __clone() {
// Force a clone of the nested Address object
$this->address = clone $this->address;
}
}How the Code Works
- Instantiating the Objects: When you create a
Userwith anAddress, both objects exist in memory, and theUserholds a reference to theAddress. - Cloning the Object: When you execute
$clonedUser = clone $originalUser;, PHP copies the$nameproperty directly. - Triggering
__clone(): PHP then executes the__clone()method on the new$clonedUserinstance. - Cloning the Reference: Inside
__clone(),$this->address = clone $this->address;creates a brand new copy of theAddressobject and assigns it to the cloned user’s address property.
As a result, modifying $clonedUser->address->city
will not affect $originalUser->address->city.
Deep Cloning Arrays of Objects
If your object contains an array of other objects, you must loop
through the array within the __clone() method to clone each
nested object individually:
class Department {
public string $name;
public array $employees = []; // Array of Employee objects
public function __clone() {
foreach ($this->employees as $key => $employee) {
if (is_object($employee)) {
$this->employees[$key] = clone $employee;
}
}
}
}This approach guarantees that every object reference contained within the array is duplicated, preventing shared memory leaks between your cloned instances.