Copying objects in PHP 5 using clone

In PHP 4 object variables were simple. Assigning one object to another worked exactly as you'd expect.

$object1->title = "Title One";
$object2 = $object1;
$object2->title = "Title Two";
print $object1->title; // returns "Title One"

You could make a copy of the original, and modify your copy with full assurance that your original would remain untouched.

That changed in PHP 5. Now when you assign an object to a new variable. The 2 variables remain inextricably linked.

$object1->title = "Title One";
$object2 = $object1;
$object2->title = "Title Two";
print $object1->title; // returns "Title Two"

In order to create an actual copy and not simply a reference to an existing object, PHP introduced the clone keyword.

$object1->title = "Title One";
$object2 = clone $object1;
$object2->title = "Title Two";
print $object1->title; // returns "Title One"

Now you can modify your newly cloned object to your heart's delight, while keeping intact your original.

For more information about Objects, References and Cloning in PHP read these pages.

Today I came across a less intuitive example of this object assignment gotcha. It involves storing objects statically inside a function. In this example, you might expect to grab an object using the load_object() function and make changes to the returned object without affecting the static cache inside that function. You'd be wrong.

function load_object($id) {
  static $nodes = array();
 
  if (empty($nodes[$id])) {
    $node = new stdClass;
    $node->title = "My Title";
 
    $nodes[$id] = $node;
  }
 
  return $nodes[$id]; // returned object simply points to $nodes[$id] instead of creating a copy
}
 
$obj = load_object(1);
 
print $obj->title; // returns "My Title"
 
$obj->title = "My Changed Title"; // Changing the title in this object also changes the original $nodes[1] object
 
// Load the statically cached $nodes[1] object into a new variable
$obj2 = load_object(1);
 
print $obj2->title; // returns "My Changed Title"

In order to keep your static cache objects preserved, you'll need to again use the clone keyword.

function load_object($id) {
  static $nodes = array();
 
  if (empty($nodes[$id])) {
    $node = new stdClass;
    $node->title = "My Title";
 
    $nodes[$id] = $node;
  }
 
  return clone $nodes[$id]; // returned object is an unlinked copy instead of a reference to the original
}
 
$obj = load_object(1);
 
print $obj->title; // returns "My Title"
 
$obj->title = "My Changed Title"; // Changing the title in this object also changes the original $nodes[1] object
 
// Load the statically cached $nodes[1] object into a new variable
$obj2 = load_object(1);
 
print $obj2->title; // returns "My Changed Title"
Tags:

Comments

copy object

this example is very simple and useful