Home > PHP, PHP Tutorials, PHP5 Magic Methods, PHP5 OOPS Tutorials > PHP5 Tutorial – Magic Methods – __clone() method

PHP5 Tutorial – Magic Methods – __clone() method

November 5th, 2007 admin Leave a comment Go to comments

Before I begin to explain the use of a __clone() method, lets try and understand what does object cloning mean.

To clone an object means to create a duplicate of an object. With regular variables $a = $b means that a new variable $a gets created that contains the value of $b. This means that 2 variables get created.

With objects $obj2 = $obj1 does not mean that a new object i.e. $obj2 gets created. When we execute $obj2 = $obj1, the reference of $obj1 is assigned to $obj2. This means that $obj1 and $obj2 point to the same memory space. Look at the diagram below.

PHP5 Tutorial - Magic Method - __clone() method

Lets look at an example where only references are assigned to another object:

class Customer {
	private $name;
 
	public function setName($name) {
		$this->name = $name;
	}
 
	public function getName() {
		return $this->name;
	}
}
 
$c1 = new Customer();
$c1->setName("Sunil");
 
$c2 = $c1; //only reference or memory assigned to $c2
 
$c2->setName("Vishal");
 
echo $c1->getName()."\n";
echo $c2->getName()."\n";

Output:
Vishal
Vishal

In the above example, $c2 has the reference of $c1; therefore, when you set a new name in the $c2 object – $c1 object changes as well. Therefore, when an object is assigned as a reference; changes made to one object are also reflected in the other.

Therefore, to create a new $obj2 object we must clone an object to create a new one. To clone an PHP5 Object a special keyword i.e. clone is used. Example below:

        $obj2 = clone $obj1;

After the above line is executed $obj2 with a new memory space is created with the data members having the same value as that of $obj1. This is also referred to as shallow copy.




PHP5 Tutorial - Magic Method - __clone() method

The above technique works with a class having data members that are of intrinsic type i.e. int, boolean, string, float, etc.. However, this technique will not work with a class that has a data member which is an object of another class. In such a scenario, the cloned object continues to share the reference of the data member object of the class that was cloned.

So, how do we resolve this issue? Doing a regular shallow copy won’t help us. To allow aggregated objects (i.e. data members that are objects of another class) to also get cloned properly we need to use the concept of ‘deep copy‘ as opposed to ‘shallow copy‘. To implement a ‘deep copy‘ you should implement the magic method __clone().

You could also provide the implementation of __clone() magic method even when you don’t have an aggregated object. You would want to do this for providing necessary clean up operations, conversions or validations.

Lets explore a very simple example of cloning intrinsic data types:

class Customer {
	private $name;
 
	public function setName($name) {
		$this->name = $name;
	}
 
	public function getName() {
		return $this->name;
	}
 
	public function __clone() {
		$c = new Customer();
		$c->setName($this->name);
		return $c;
	}
 
}
 
$c1 = new Customer();
$c1->setName("Sunil");
 
$c2 = clone $c1; //new object $c2 created
 
$c2->setName("Vishal");
 
echo $c1->getName()."\n";
echo $c2->getName()."\n";

Output:
Sunil
Vishal

In the above example, observe the line where the statement $c2 = clone $c1 is executed. This is internally represented as $c2 = $c1.__clone(). However, you cannot explicitly call the __clone() method on an object as the __clone() is automatically called. Now that $c1 and $c2 are two individual objects, changes made to one object is not reflected in the other.




Cloning aggregate objects (i.e. data members that are objects of another class)

To clone a class having aggregated objects, you should perform ‘deep copy‘. Please refer to the example below:

class Order {
	private $order_id;
	private $customer;
 
	public function setOrderId($order_id) {
		$this->order_id = $order_id;
	}
 
	public function getOrderId() {
		return $this->order_id;
	}
 
	public function setCustomer(Customer $customer) {
		$this->customer = clone $customer;
	}
 
	public function getCustomer() {
		return $this->customer;
	}
 
	public function __clone() {
 
		$o = new Order();
		$o->setOrderId($this->order_id);
 
 
		//force a copy of the same object to itself, otherwise
		//it takes the same instance. Seems like a bug to me
		$this->customer = clone $this->customer;
		$o->setCustomer($this->customer);
		return $o;
	}
 
}
 
class Customer {
	private $name;
 
	public function setName($name) {
		$this->name = $name;
	}
 
	public function getName() {
		return $this->name;
	}
 
	public function __clone() {
		$c = new Customer();
		$c->setName($this->name);
		return $c;
	}
 
}
 
$c = new Customer();
$c->setName("Sunil");
 
$o1 = new Order();
$o1->setOrderId("OD0001");
$o1->setCustomer($c);
 
$o2 = clone $o1;
 
$o2->getCustomer()->setName("Vishal");
 
var_dump($c);
var_dump($o1);
var_dump($o2);

Output:
object(Customer)#1 (1) {
[”name:private”]=>
string(5) “Sunil”
}
object(Order)#2 (2) {
[”order_id:private”]=>
string(6) “OD0001″
[”customer:private”]=>
object(Customer)#3 (1) {
[”name:private”]=>
string(5) “Sunil”
}
}
object(Order)#4 (2) {
[”order_id:private”]=>
string(6) “OD0001″
[”customer:private”]=>
object(Customer)#6 (1) {
[”name:private”]=>
string(6) “Vishal”
}
}

In the above example both $o1 and $o2 have their own set of customer objects, therefore changes made to one object is not reflected in another. This example implements the concepts of ‘deep copy‘.

A special note on $this->customer = clone $this->customer; For some reason it is necessary to do this for proper working of aggregated cloning.

I hope this tutorial was helpful. Please feel free to leave behind any comments or questions that you might have.

Related Posts on PHP5 Tutorial – Object Oriented Programming (OOPS)

  1. PHP5 Tutorial – Learn to create a PHP5 Class
  2. PHP5 Tutorial – Learn to Create a PHP5 Class Object
  3. PHP5 Tutorial – Defining Attributes of a PHP5 Class
  4. PHP5 Tutorial – Defining Methods of a PHP5 Class
  5. PHP5 Tutorial – Creating a PHP5 Constructor __construct()
  6. PHP5 Tutorial OOPS – Creating a PHP5 Destructor __destruct()
  7. PHP5 Tutorial OOPS – PHP5 Class Access Specifiers – public, private and protected
  8. PHP5 Tutorial – Magic Methods – __toString() method
  9. PHP5 Tutorial – Magic Methods – __get() and __set()
  10. PHP5 Tutorial – Magic Methods – __isset() and __unset()
  11. PHP5 Tutorial – Magic Methods – __call() method
  12. PHP5 Tutorial – Magic Methods – __autoload() method
  13. PHP5 Tutorial – Magic Methods – __sleep() and __wakeup()
  14. PHP5 Tutorial – Magic Methods – __clone() method

Warning: session_start(): Cannot send session cookie - headers already sent by (output started at /home/sunilb/www.sunilb.com/wp-content/plugins/all-in-one-seo-pack/aioseop.class.php:245) in /home/sunilb/www.sunilb.com/wp-content/plugins/mycaptcha/MyCaptcha.php on line 41

Warning: session_start(): Cannot send session cache limiter - headers already sent (output started at /home/sunilb/www.sunilb.com/wp-content/plugins/all-in-one-seo-pack/aioseop.class.php:245) in /home/sunilb/www.sunilb.com/wp-content/plugins/mycaptcha/MyCaptcha.php on line 41
  1. maniac
    November 10th, 2007 at 00:08 | #1

    Thanks, helpful

  2. Stephan
    November 17th, 2007 at 18:24 | #2

    Very good & interesting sum up. Thanks.

  3. June 17th, 2008 at 13:26 | #3

    Very systematic Explanation than x & good luck

  4. Mehran
    June 17th, 2008 at 19:07 | #4

    Really nice and easy explanation on the subject:-) In fact some of the best I ever read! U know the art of making it simple, man:-)

  5. mescalito2
    July 25th, 2008 at 03:25 | #5

    that’s what I needed, well done thanks!

  6. ln8r
    September 18th, 2008 at 03:34 | #6

    You’ve overcomplicated this. First, if you just need to clone the object exactly then don’t define a __clone() method. It will be handled automatically by PHP. So you don’t have to define __clone() at all in the Customer class.

    Second, you don’t have to make a copy of the object that you’re cloning. You can just operate on $this and PHP will take care of the rest. So rather that manually cloning the Order object in the __clone() method it can be just one line:

    public function __clone {
    $this->setCustomer($this->customer);
    }

  7. admin
    November 15th, 2008 at 19:34 | #7

    My reply to In8r:

    public function __clone {
    $this->setCustomer($this->customer);
    }

    As per your above statement, you are not copying the customer object – but only assigning the memory address of the existing customer object to the new object.

    This means if the original customer object were to be deleted – the newly created pointer would become NULL.

    That is the reason we need to clone.

    Let me know if you need more clarifications.

    Regards,
    Suniil

  8. kirubakar
    December 3rd, 2008 at 11:48 | #8

    Thanks, Its gud. But I cant understand the concept of Cloning aggregate objects at $o2 =clone $o1.Could u say everything in detail thru mail or this forum . pls say step by step wat will hapen at this stage $o2 =clone $o1

  9. admin
    December 3rd, 2008 at 22:18 | #9

    Hi Kirubakar,

    When you do $o2 = $o1, then the memory of $o1 is assigned to $o2. This means that both the variables point to the same memory location. Therefore if you change data in memory – both the objects get to see it as they point to same memory location.

    However, if this is your requirement – then its good. But in a real world scenario you would want to create another copy of $o1 so that if you make changes to $o1 – it does not get reflected to $o2.

    Cloning means to allocate a new memory location to $o2 and copy the contents of $o1 into the newly allocated memory location.

    Hope this explanation is clear.

    Regards,
    Suniil

  10. kirubakar
    December 4th, 2008 at 12:49 | #10

    Thank u for ur care, But I asked when this function
    public function __clone() {
    $o = new Order();
    $o->setOrderId($this->order_id);
    $this->customer = clone $this->customer;
    $o->setCustomer($this->customer);
    return $o;
    }
    will call, then what process will go here $o2->getCustomer()->setName(“Vishal”);

    Plz explain

  11. kirubakar
    December 4th, 2008 at 12:52 | #11

    hi
    In $o1->setCustomer($c); the object $o1 will it pont the memory of $c

  12. hasan
    June 2nd, 2009 at 18:10 | #12

    great wonderful and all words like this are for your tutorials

  13. July 15th, 2009 at 12:28 | #13

    i’ve learned a lot from this tutorial!!! and i want to know if are there any other topics that wasn’t discussed aside from this tutorial? coz i want to master this lesson.. thanks in advanz!!!;>

  14. July 16th, 2009 at 12:43 | #14

    THANK YOU SO MUCH!!!!
    YES I REALLY LEARNED EVERYTHING!!!!
    LOVE YOU!

  15. August 13th, 2009 at 17:30 | #15

    Its very clear and good! :)

  16. Netemp
    August 16th, 2009 at 13:32 | #16

    Hey Sunil,

    Thanks for taking the time and sharing your knowledge. Really Commnedable.

    Take Care

  17. September 3rd, 2009 at 15:43 | #17

    Dear Suniil,

    thank you for this clear, compact tutorial. Just what I was looking for.
    Now the real stuff starts by implementing it.

    Wonderful how you share your knowledge to the world. Looks like the world is changing to a sharing place.

    Blessings to you
    Steven

  18. avare
    October 5th, 2009 at 14:24 | #18

    Thanks! It is really helpful for a person who is beginner about oo programming issues in PHP.

  19. October 12th, 2009 at 03:02 | #19

    Hey Sunil,

    I gone thru all ur articles, all are awesome. I was in search of some oops concept, when I searched “PHP oops” in google. The first result was you, thats wonderful.

    It helped me a lot to understand most of the OOPS concept in PHP.

    Again wud say thank you very much, keep posting.

    jassy

  20. Zainuddin
    October 16th, 2009 at 23:33 | #20

    Hi Sunil
    Artical is really good. providing very valuable information in such a simple manner.

    Thanks
    Zainuddin

  21. November 14th, 2009 at 11:32 | #21

    I know oops concept well,but these tutorial help me to understand deeply with well &simple examples.thank u .

  22. Savita A S
    December 17th, 2009 at 19:05 | #22

    Thanks for the wonderful tutorial.
    This is the best site for begineers

  23. siva
    January 12th, 2010 at 15:19 | #23

    Sunil,

    This article is very helpful to understand the OOPS Concepts.

    Thanks
    Siva

  24. January 13th, 2010 at 01:06 | #24

    Nice Tutorial

  25. Ibrahim
    January 19th, 2010 at 21:07 | #25

    hey you really did a great tutorial man.. and the explanation was too helpfull.. and i reallt expect something more from you and waiting to see the new updates .. if you can give something like sessions, cookies,, it wil help so much new comers to understand and the way of your explanation :X.. no words Man .. u rock

  26. hiren
    March 11th, 2010 at 17:37 | #26

    still i hadn’t found such a clear description before i read this.

    keep on writing!

  1. No trackbacks yet.
Enter this code to leave comment (Sorry, but bots get me crazy :) )