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
PHP Web Scraping of JavaScript Generated Contents
Increasing PHP Memory_Limit. at What Point Does It Become Insane
Mysqli Prepared Statement Column with Variable
MySQL Encryption/Storing Sensitive Data,
Convert Clickable Anchor Tags to Plain Text in HTML Document
Pdo: Invalid Parameter Number: Mixed Named and Positional Parameters
Which Compression Method to Use in PHP
Storing Datetime as Utc in PHP/Mysql
Convert Lat/Longs to X/Y Co-Ordinates
Laravel 5 - Env() Always Returns Null
How to Debug Why Simplest MySQL Query Returns False
Laravel Eloquent Sort by Relation Table Column
Proper Session Hijacking Prevention in PHP
Simple Way to Read Single Record from MySQL
Laravel Validation: Exists with Additional Column Condition - Custom Validation Rule