php-object-cloning

When to clone objects in PHP

In PHP 4, copying an object was made by assigning from one variable to another, which was a source of many bugs.

class MyClass {}
$first = new MyClass();
$second = $first;
// PHP 4: $second and $first are 2 distinct objects
// PHP 5: $second and $first refer to one object

Prior to PHP5, equivalence tests would tell you whether all fields were the same (==) or whether both variables were objects (===), but not whether they pointed to the same object.
In PHP, objects are always assigned and passed around by reference. This means that when my previous example is run with PHP 5, $first and $second contain references to the same object instead of two copies.

Using the clone keyword you can produce a by-value copy:

class CopyMe {}
$first = new CopyMe();
$second = clone $first;
// PHP 5: $second and $first are 2 distinct objects

Moreover, you can control what is copied when clone is invoked on an object. You do this by implementing a built-in method called __clone() which is called automatically when the clone keyword is used and is run on the copied object and not the original.

class Person {
	private $name;
	private $age;
	private $id;
	function __construct($name, $age) {
		$this->name = $name;
		$this->age = $age;
	}
	function setId($id) {
		$this->id = $id;
	}
	function __clone() {
		$this->id = 0;
	}
}
$person = new Person ( "john", 30 );
$person->setId ( 5 );
$person2 = clone $person;
/* 
   $person2 :
   name: john
   age: 30
   id: 0 
 */

As you can see, anything I do in __clone() overwrites the default copy. In this case, I ensure that the copied object’s $id property is set to zero.
A shallow copy ensures that primitive properties are copied from the old object to the new. Object properties, though, are copied by reference, which may not be what you want or expect when cloning an object.
In following sample both Person objects hold references to the same Account object property:

class Account {
	public $balance;
	function __construct($balance) {
		$this->balance = $balance;
	}
}
class Person {
	private $name;
	private $age;
	private $id;
	public $account;
	function __construct($name, $age, Account $account) {
		$this->name = $name;
		$this->age = $age;
		$this->account = $account;
	}
	function setId($id) {
		$this->id = $id;
	}
	function __clone() {
		$this->id = 0;		
	}
}
$person = new Person ( "angi", 34, new Account (200) );
$person->setId (43);
$person2 = clone $person;
$person->account->balance += 10;
print $person2->account->balance;
// This gives the output: 210

If I do not want an object property to be shared after a clone operation then it is up to me to clone it explicitly in the __clone() method:

function __clone() {
   $this->id = 0;
   $this->account = clone $this->account;
}
email-newsletter

Dev'Letter

Professional opinion about Web Development Techniques, Tools & Productivity.
Only once a month!

Any suggestion on what to write next time ? Submit now

Opinions

avatar
550
  Subscribe  
Notify of

Related Posts