Object Copy Versus Clone in PHP

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.

Deep cloning an object : Clone vs Serialize

You can control what exactly gets cloned by overriding the __clone() method in your Course entity. You can set id to null and clone referenced objects if you need a deep copy.

The serialization/unserialization feels like a hack, so I recommend against using it.

In PHP can someone explain cloning vs pointer reference?

Basically, there are two ways variables work in PHP...

For everything except objects:

  1. Assignment is by value (meaning a copy occurs if you do $a = $b.
  2. Reference can be achieved by doing $a = &$b (Note the reference operator operates upon the variable, not the assignment operator, since you can use it in other places)...
  3. Copies use a copy-on-write tehnique. So if you do $a = $b, there is no memory copy of the variable. But if you then do $a = 5;, the memory is copied then and overwritten.

For objects:

  1. Assignment is by object reference. It's not really the same as normal variable by reference (I'll explain why later).
  2. Copy by value can be achieved by doing $a = clone $b.
  3. Reference can be achieved by doing $a = &$b, but beware that this has nothing to do with the object. You're binding the $a variable to the $b variable. It doesn't matter if it's an object or not.

So, why is assignment for objects not really reference? What happens if you do:

$a = new stdclass();
$b = $a;
$a = 4;

What's $b? Well, it's stdclass... That's because it's not writing a reference to the variable, but to the object...

$a = new stdclass();
$a->foo = 'bar';
$b = $a;
$b->foo = 'baz';

What's $a->foo? It's baz. That's because when you did $b = $a, you are telling PHP to use the same object instance (hence the object reference). Note that $a and $b are not the same variable, but they do both reference the same object.

One way of thinking about it, is to think of all variables which store an object as storing the pointer to that object. So the object lives somewhere else. When you assign $a = $b where $b is an object, all you're doing is copying that pointer. The actual variables are still disjoint. But when you do $a = &$b, you're storing a pointer to $b inside of $a. Now, when you manipulate $a it cascades the pointer chain to the base object. When you use the clone operator, you're telling PHP to copy the existing object, and create a new one with the same state... So clone really just does a by-value copy of the varaible...

So if you noticed, I said the object is not stored in an actual variable. It's stored somewhere else and nothing but a pointer is stored in the variable. So this means that you can have (and often do have) multiple variables pointing to the same instance. For this reason, the internal object representation contains a refcount (Simply a count of the number of variables pointing to it). When an object's refcount drops to 0 (meaning that all the variables pointing to it either go out of scope, or are changed to somethign else) it is garbaged collected (as it is no longer accessable)...

You can read more on references and PHP in the docs...

Disclaimer: Some of this may be oversimplification or blurring of certain concepts. I intended this only to be a guide to how they work, and not an exact breakdown of what goes on internally...

Edit: Oh, and as for this being "clunky", I don't think it is. I think it is really useful. Otherwise you'd have variable references being passed around all over the place. And that can yield some really interesting bugs when a variable in one part of an application affects another variable in another part of the app. And not because it's passed, but because a reference was made somewhere along the line.

In general, I don't use variable references that much. It's rare that I find an honest need for them. But I do use object references all the time. I use them so much, that I'm happy that they are the default. Otherwise I'd need to write some operator (since & denotes a variable reference, there'd need to be another to denote an object reference). And considering that I rarely use clone, I'd say that 99.9% of use cases should use object references (so make the operator be used for the lower frequency cases)...

JMHO

I've also created a video explaining these differences. Check it out on YouTube.

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...

What's the advantage of `clone` over instantiating a new object in PHP?

In this specific situation there will be no difference. There would be a difference if the object had other properties (they would get reset if creating a new instance instead of cloning).

There are also other situations where clone can be appropriate:

  • If the class of the object does not have a constructor that is accessible to you
  • If the class of the object does have a constructor, but you don't know what values you should pass to it; in general, if you don't know how you would construct a duplicate object
  • If constructing a new object has side effects that are undesirable
  • If the object has internal state and you don't know how to move from a "freshly constructed" state to that of the instance you already have

PHP Deep Object Copy/Clone

If you have full access to your classes, you can implement __clone() in all of them and then use the clone keyword. Otherwise the clone keyword will just create a shallow copy of the topmost object, while potential references within this object will continue to point at their original targets. The __clone() method also gives you more control, but may create endless loops with cyclic references, if you don't deal with them explicitly.

The serialization technique generally works, does not die on cyclic references, but is more expensive in terms of memory and CPU.



Related Topics



Leave a reply



Submit