How Object Cloning and __clone Work in PHP
In PHP, object cloning allows developers to create a copy of an
existing object using the clone keyword. This article
explains how object cloning works, the difference between shallow and
deep copying, and how the __clone() magic method can be
used to customize the cloning behavior for nested objects or specific
property adjustments.
Understanding Object Cloning in PHP
By default, when you assign an object to a new variable in PHP (e.g.,
$b = $a), you are not copying the object. Instead, you are
copying the reference to that object. Both variables will point to the
same instance in memory.
To create a completely separate copy of an object, PHP provides the
clone keyword.
$copyOfObject = clone $originalObject;When you use the clone keyword, PHP performs a
shallow copy of the object. This means: * All
properties of the original object are copied to the new object. * If any
of those properties hold value types (like strings, integers, or
arrays), they are copied by value. * If any property holds a reference
to another object, only the reference is copied. The cloned object and
the original object will still point to the same nested object.
What the __clone() Magic Method Does
To solve the limitations of a shallow copy and perform a deep
copy, PHP provides the __clone() magic method.
The __clone() method is automatically called on the
newly cloned object once the cloning process is complete. It cannot be
called directly. Within this method, you can define custom behavior,
such as cloning nested objects or resetting specific identifiers (like
database IDs or timestamps) for the new copy.
Code Example: Implementing a Deep Copy
Here is how you can use the __clone() method to clone
nested objects and reset properties:
class NestedConfiguration {
public string $theme = 'dark';
}
class UserProfile {
public string $username;
public ?int $id;
public NestedConfiguration $config;
public function __construct(string $username) {
$this->username = $username;
$this->id = 101; // Example database ID
$this->config = new NestedConfiguration();
}
// This magic method is executed automatically on the cloned object
public function __clone() {
// Force a copy of the nested object to prevent shared reference
$this->config = clone $this->config;
// Reset the unique identifier for the new clone
$this->id = null;
}
}
// Usage
$originalUser = new UserProfile('Alice');
$clonedUser = clone $originalUser;
// Modifying the cloned object does not affect the original
$clonedUser->config->theme = 'light';
echo $originalUser->config->theme; // Outputs: dark
echo $clonedUser->config->theme; // Outputs: light
echo $clonedUser->id; // Outputs: (null)In this example, without the __clone() method, changing
$clonedUser->config->theme would have also changed
$originalUser->config->theme because they shared the
same reference to the NestedConfiguration object. By
cloning the nested object inside __clone(), we achieved a
deep copy. Additionally, resetting $this->id to
null ensures the cloned object does not inherit the primary
key of the original database record.