What Is Object Cloning in PHP

what is Object Cloning in php?

Object cloning is the act of making a copy of an object. As Cody pointed out, cloning in PHP is done by making a shallow copy of the object. This means that internal objects of the cloned object will not be cloned, unless you explicitly instruct the object to clone these internal objects too, by defining the magic method __clone().

If you don't utilize the __clone method, the internal objects of the new object will be references to the same objecs in memory as the internal objects of the original object that was cloned.

Consider these examples:

// in this exampe the internal member $_internalObject of both objects
// reference the same instance of stdClass in memory.
class CloneableClass
{
private $_internalObject;

public function __construct()
{
// instantiate the internal member
$this->_internalObject = new stdClass();
}
}

$classA = new CloneableClass();
$classB = clone $classA;

// in this exampe the internal member $_internalObject of both objects
// DON'T reference the same instance of stdClass in memory, but are inividual instances
class CloneableClass
{
private $_internalObject;

public function __construct()
{
// instantiate the internal member
$this->_internalObject = new stdClass();
}

// on clone, make a deep copy of this object by cloning internal member;
public function __clone()
{
$this->_internalObject = clone $this->_internalObject;
}
}

$classA = new CloneableClass();
$classB = clone $classA;

Use cases for cloning would for instance be a case where you don't want outside objects to mess with the internal state of an object.

Let's say you have a class User with a internal object Address.

class Address
{
private $_street;
private $_streetIndex;
private $_city;
// etc...

public function __construct( $street, $streetIndex, $city /* etc.. */ )
{
/* assign to internal values */
}
}

class User
{
// will hold instance of Address
private $_address;

public function __construct()
{
$this->_address = new Address( 'somestreet', '1', 'somecity' /* etc */ );
}

public function getAddress()
{
return clone $this->_address;
}
}

For arguments sake, let's say you don't want outside objects to mess with the internal Address of User objects, but you do want to be able to give them a copy of the Address object. The above example illustrates this. The getAddress method returns a clone of the address object to calling objects. This means that if the calling object alters the Address object, the internal Address of User will not change. If you didn't give a clone, then the outside object would be able to alter the internal Address of User, because a reference is given by default, not a clone.

Hope this all makes some sense.

PS.:
Be aware though, that if Address would also have internal objects, you would have to make sure Address makes a deep copy of itself on cloning (as per my second example of this post) by defining __clone() in Address. Otherwise you will get headaches of trying to figure out why your data is screwed.

How do I create a copy of an object in PHP?

In PHP 5+ objects are passed by reference. In PHP 4 they are passed by value (that's why it had runtime pass by reference, which became deprecated).

You can use the 'clone' operator in PHP5 to copy objects:

$objectB = clone $objectA;

Also, it's just objects that are passed by reference, not everything as you've said in your question...

Use of __clone in PHP?

void __clone ( void )

Once the cloning is complete, if a __clone() method is defined, then
the newly created object's __clone() method will be called, to allow
any necessary properties that need to be changed.

http://php.net/manual/en/language.oop5.cloning.php#object.clone

So yes, it's a callback after the clone operation has finished. Nothing more, nothing less.

How to handle __clone for child class object properties

First of all, your Child_A does not extend Parent_A, so this construction

class Child_A {

function __construct(A_2 $a_2){
parent::__construct(new A_1());
}
}

results with fatal error on the first attempt to instantiate the class.

Secondly, you make no use of $a_2 there, so Child_A::__clone will result with notice of undefined variable A_2.

Finally, to answer the question - no, if not explicitly called, parent's __clone is not invoked. The recommended solution is to let the child handle clone of its own properties only, and let parent take care about its properties:

class Parent_A
{
protected $a_1;

function __construct(A_1 $a_1)
{
$this->a_1 = $a_1;
}

function __clone()
{
$this->a_1 = clone $this->a_1;
}
}

class Child_A extends Parent_A
{
protected $a_2;

function __construct(A_2 $a_2)
{
$this->a_2 = $a_2;
parent::__construct(new A_1);
}

function __clone()
{
$this->a_2 = clone $this->a_2;
return parent::__clone();
}
}

PHP Object Assignment vs Cloning

Objects are abstract data in memory. A variable always holds a reference to this data in memory. Imagine that $foo = new Bar creates an object instance of Bar somewhere in memory, assigns it some id #42, and $foo now holds this #42 as reference to this object. Assigning this reference to other variables by reference or normally works the same as with any other values. Many variables can hold a copy of this reference, but all point to the same object.

clone explicitly creates a copy of the object itself, not just of the reference that points to the object.

$foo = new Bar;   // $foo holds a reference to an instance of Bar
$bar = $foo; // $bar holds a copy of the reference to the instance of Bar
$baz =& $foo; // $baz references the same reference to the instance of Bar as $foo

Just don't confuse "reference" as in =& with "reference" as in object identifier.

$blarg = clone $foo;  // the instance of Bar that $foo referenced was copied
// into a new instance of Bar and $blarg now holds a reference
// to that new instance

Difference between clone object and normal object

You should look at the following example

<?php

class classA {
public $x=0;
}

$a = new classA();
$a->x = 20;

echo $a->x."<br />";

$b = clone $a;

$a->x = 30;

echo $a->x."<br />";

echo $b->x."<br />"; // 20 because x was 20 before cloning $a to $b

$a->x = 50;

echo $a->x."<br />"; // changed to 50

echo $b->x."<br />"; // stil 20, $a

$c = new classA();

echo $c->x;

Using cloning make, you have property x in object $b the same as in object $a because cloning simple copies object. And when creating new object, you will have new object and property value will be 0.

Cloning is simple copying object because by default for objects:

$a = $b;

PHP won't do copying (as for simple types) but will point to exact place in memory.

So for simple types you use:

$a = 5;
$b = $a;

if you want to make a copy, but for objects you need to use clone:

$a = new classA();
$a->x = 20;
$b = clone $a;

to have the same effect.

You should look in manual at Object and references and Cloning to understand those things.



Related Topics



Leave a reply



Submit