Php clone object to this

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.

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

Источник

Php clone object to this

Creating a copy of an object with fully replicated properties is not always the wanted behavior. A good example of the need for copy constructors, is if you have an object which represents a GTK window and the object holds the resource of this GTK window, when you create a duplicate you might want to create a new window with the same properties and have the new object hold the resource of the new window. Another example is if your object holds a reference to another object which it uses and when you replicate the parent object you want to create a new instance of this other object so that the replica has its own separate copy.

An object copy is created by using the clone keyword (which calls the object’s __clone() method if possible).

$copy_of_object = clone $object;

When an object is cloned, PHP will perform a shallow copy of all of the object’s properties. Any properties that are references to other variables will remain references.

Читайте также:  Window location hash html

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.

Example #1 Cloning an object

class SubObject
static $instances = 0 ;
public $instance ;

public function __construct () $this -> instance = ++ self :: $instances ;
>

public function __clone () $this -> instance = ++ self :: $instances ;
>
>

class MyCloneable
public $object1 ;
public $object2 ;

function __clone ()
// Force a copy of this->object, otherwise
// it will point to same object.
$this -> object1 = clone $this -> object1 ;
>
>

$obj -> object1 = new SubObject ();
$obj -> object2 = new SubObject ();

print( «Original Object:\n» );
print_r ( $obj );

print( «Cloned Object:\n» );
print_r ( $obj2 );

The above example will output:

Original Object: MyCloneable Object ( [object1] => SubObject Object ( [instance] => 1 ) [object2] => SubObject Object ( [instance] => 2 ) ) Cloned Object: MyCloneable Object ( [object1] => SubObject Object ( [instance] => 3 ) [object2] => SubObject Object ( [instance] => 2 ) )

It is possible to access a member of a freshly cloned object in a single expression:

Example #2 Access member of freshly cloned object

The above example will output something similar to:

User Contributed Notes 14 notes

I think it’s relevant to note that __clone is NOT an override. As the example shows, the normal cloning process always occurs, and it’s the responsibility of the __clone method to «mend» any «wrong» action performed by it.

Here is test script i wrote to test the behaviour of clone when i have arrays with primitive values in my class — as an additonal test of the note below by jeffrey at whinger dot nl

private $myArray = array();
function pushSomethingToArray ( $var ) array_push ( $this -> myArray , $var );
>
function getArray () return $this -> myArray ;
>

//push some values to the myArray of Mainclass
$myObj = new MyClass ();
$myObj -> pushSomethingToArray ( ‘blue’ );
$myObj -> pushSomethingToArray ( ‘orange’ );
$myObjClone = clone $myObj ;
$myObj -> pushSomethingToArray ( ‘pink’ );

//testing
print_r ( $myObj -> getArray ()); //Array([0] => blue,[1] => orange,[2] => pink)
print_r ( $myObjClone -> getArray ()); //Array([0] => blue,[1] => orange)
//so array cloned

I ran into the same problem of an array of objects inside of an object that I wanted to clone all pointing to the same objects. However, I agreed that serializing the data was not the answer. It was relatively simple, really:

Читайте также:  Сколько осталось до даты php

Note, that I was working with a multi-dimensional array and I was not using the Key=>Value pair system, but basically, the point is that if you use foreach, you need to specify that the copied data is to be accessed by reference.

Another gotcha I encountered: like __construct and __desctruct, you must call parent::__clone() yourself from inside a child’s __clone() function. The manual kind of got me on the wrong foot here: «An object’s __clone() method cannot be called directly.»

Here is a basic example about clone issue. If we use clone in getClassB method. Return value will be same as new B() result. But it we dont use clone we can effect B::$varA.

class A
protected $classB;

public function __construct() $this->classB = new B();
>

public function getClassB()
return clone $this->classB;
>
>

class B
protected $varA = 2;

public function getVarA()
return $this->varA;
>

public function setVarA()
$this->varA = 3;
>
>

echo $a->getClassB()->getVarA() . PHP_EOL;// with clone -> 2, without clone it returns -> 3

echo $classB->getVarA() . PHP_EOL; // returns always 3

Here are some cloning and reference gotchas we came up against at Last.fm.

1. PHP treats variables as either ‘values types’ or ‘reference types’, where the difference is supposed to be transparent. Object cloning is one of the few times when it can make a big difference. I know of no programmatic way to tell if a variable is intrinsically a value or reference type. There IS however a non-programmatic ways to tell if an object property is value or reference type:

$a = new A ;
$a -> p = ‘Hello’ ; // $a->p is a value type
var_dump ( $a );

$ref =& $a -> p ; // note that this CONVERTS $a->p into a reference type!!
var_dump ( $a );

?>

2. unsetting all-but-one of the references will convert the remaining reference back into a value. Continuing from the previous example:

?>

I interpret this as the reference-count jumping from 2 straight to 0. However.

2. It IS possible to create a reference with a reference count of 1 — i.e. to convert an property from value type to reference type, without any extra references. All you have to do is declare that it refers to itself. This is HIGHLY idiosyncratic, but nevertheless it works. This leads to the observation that although the manual states that ‘Any properties that are references to other variables, will remain references,’ this is not strictly true. Any variables that are references, even to *themselves* (not necessarily to other variables), will be copied by reference rather than by value.

Here’s an example to demonstrate:

class ByRef
var $prop ;
function __construct () < $this ->prop =& $this -> prop ; >
>

$a = new ByVal ;
$a -> prop = 1 ;
$b = clone $a ;
$b -> prop = 2 ; // $a->prop remains at 1

$a = new ByRef ;
$a -> prop = 1 ;
$b = clone $a ;
$b -> prop = 2 ; // $a->prop is now 2

It should go without saying that if you have circular references, where a property of object A refers to object B while a property of B refers to A (or more indirect loops than that), then you’ll be glad that clone does NOT automatically make a deep copy!

Читайте также:  Исполнение кода в питоне

function __clone ()
$this -> that = clone $this -> that ;
>

$a = new Foo ;
$b = new Foo ;
$a -> that = $b ;
$b -> that = $a ;

$c = clone $a ;
echo ‘What happened?’ ;
var_dump ( $c );

This base class automatically clones attributes of type object or array values of type object recursively. Just inherit your own classes from this base class.

class clone_base
public function __clone ()
$object_vars = get_object_vars ( $this );

foreach ( $object_vars as $attr_name => $attr_value )
if ( is_object ( $this -> $attr_name ))
$this -> $attr_name = clone $this -> $attr_name ;
>
else if ( is_array ( $this -> $attr_name ))
// Note: This copies only one dimension arrays
foreach ( $this -> $attr_name as & $attr_array_value )
if ( is_object ( $attr_array_value ))
$attr_array_value = clone $attr_array_value ;
>
unset( $attr_array_value );
>
>
>
>
>
?>

Example:
class foo extends clone_base
public $attr = «Hello» ;
public $b = null ;
public $attr2 = array();

public function __construct ()
$this -> b = new bar ( «World» );
$this -> attr2 [] = new bar ( «What’s» );
$this -> attr2 [] = new bar ( «up?» );
>
>

class bar extends clone_base
public $attr ;

public function __construct ( $attr_value )
$this -> attr = $attr_value ;
>
>

$f1 = new foo ();
$f2 = clone $f1 ;
$f2 -> attr = «James» ;
$f2 -> b -> attr = «Bond» ;
$f2 -> attr2 [ 0 ]-> attr = «Agent» ;
$f2 -> attr2 [ 1 ]-> attr = «007» ;

echo «f1.attr keyword»>. $f1 -> attr . «\n» ;
echo «f1.b.attr keyword»>. $f1 -> b -> attr . «\n» ;
echo «f1.attr2[0] keyword»>. $f1 -> attr2 [ 0 ]-> attr . «\n» ;
echo «f1.attr2[1] keyword»>. $f1 -> attr2 [ 1 ]-> attr . «\n» ;
echo «\n» ;
echo «f2.attr keyword»>. $f2 -> attr . «\n» ;
echo «f2.b.attr keyword»>. $f2 -> b -> attr . «\n» ;
echo «f2.attr2[0] keyword»>. $f2 -> attr2 [ 0 ]-> attr . «\n» ;
echo «f2.attr2[1] keyword»>. $f2 -> attr2 [ 1 ]-> attr . «\n» ;
?>

Источник

PHP copy all object properties to this

Now, in the class MyObject , there is a non-static function, and in there, I use the reference to «me», like $this , but I also have another object there. Is it possible, without doing $this = $myObject , to achieve more or less the same effect, like something of the sort set_object_vars($this, get_object_vars($myObject)) ?

I think your question needs a little review. Even if we had a set_object_vars() function would that be really the same effect? You would be copying the object, not referencing it. See copying vs referencing in PHP for more.

Your question doesn’t make much sense to me. ‘I use the reference to «me», like $this ‘ — especially. Maybe this is what your looking for, maybe it is not: PHP Clone class

2 Answers 2

Will do what you want I guess, but you should be aware of the following:

  1. get_object_vars will only find non-static properties
  2. get_object_vars will only find accessible properties according to scope

The according to scope part is quite important and may deserve a little more explanation. Did you know that properties scope are class dependent rather than instance dependent in PHP?

It means that in the example above, if you had a private $bar property in MyObject , get_object_vars would see it, since you are in an instance of a MyObject class. This will obviously not work if you’re trying to import instances of another class.

Источник

Оцените статью