在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值,也就是说,A与B是两个独立的对象,但B的初始值是由A对象确定的。
在php语言中,用简单的赋值语句是不能满足这种需求的。要满足这种需求虽然有很多途径,但实现clone()方法是其中最简单,也是最高效的手段。
在php5中,对象的传递方式默认为引用传递。
$copy_of_object = clone $object;//$object和$copy_of_object是不同的对象,不过$copy_of_object的值是在$object基础加$object事例对象里clone()方法改变后的实例
当对象被复制后,PHP5会对对象的所有属性执行一个“浅复制”(shallow copy)。所有的属性中的引用 仍然不变,指向原来的变量。如果定义了__clone()方法,则新创建的对象(复制生成的对象)中的__clone()方法会被调用, 可用于修改属性的值(如果有必要的话)。
核心:
$obj = new MyCloneable();
$obj2 = clone $obj;
//调用MyCloneable::__clone方法。clone方法重置想改变项,返回修改后的类的实例给pbj2.
<?php class SubObject {
public $name; public $age; public function __construct() { echo '~~~~__construct OB~~~~<br>'; $this->name = 'dayi'; $this->age = 7; }
public function __clone() { echo '~~~~333~~~~<br>'; $this->name = 'xiaobai'; $this->age = 8; } }
class MyCloneable { public $object1; public $object2;
public function __construct() { echo '~~~~__construct OA~~~~<br>';
} function __clone() { echo '~~~~2222~~~~<br>'; //print_r($this->object1); SubObject Object ( [name] => [age] => 7 ) $this->object1 = clone $this->object1; //调用SubObject::__clone方法。clone方法重置想改变项(变为xiaobai,8),返回修改后的类的实例给$this->object1. // print_r($this->object1);SubObject Object ( [name] => xiaobai [age] => 8 ) echo '&&&&444&&&&<br>'; } }
$obj = new MyCloneable(); echo '!!!1111!!!<br>'; $obj->object1 = new SubObject();
$obj->object2 = new SubObject();
$obj2 = clone $obj;//调用MyCloneable::__clone方法。clone方法重置想改变项,返回修改后的类的实例给pbj2.
echo '@@@555@@@<br><br><br>';
print("原对象:
"); var_dump($obj);
echo '<br><br><br>'; print("Cloned 对象:
"); var_dump($obj2);
###################结果###################
~~~~__construct OA~~~~ !!!1111!!! ~~~~__construct OB~~~~ ~~~~__construct OB~~~~ ~~~~2222~~~~ ~~~~333~~~~ &&&&444&&&& @@@555@@@
原对象: object(MyCloneable)#1 (2) { ["object1"]=> object(SubObject)#2 (2) { ["name"]=> string(4) "dayi" ["age"]=> int(7) } ["object2"]=> object(SubObject)#3 (2) { ["name"]=> string(4) "dayi" ["age"]=> int(7) } }
Cloned 对象: object(MyCloneable)#4 (2) { ["object1"]=> object(SubObject)#5 (2) { ["name"]=> string(7) "xiaobai" ["age"]=> int(8) } ["object2"]=> object(SubObject)#3 (2) { ["name"]=> string(4) "dayi" ["age"]=> int(7) } }
核心:所有的属性中的引用 仍然不变,指向原来的变量。
class ByRef { var $prop; function __construct() { $this->prop =& $this->prop; $this->prop1 = 'haha, i am here'; } function __clone() { $this->prop=2;// $a->prop is now 2 } } $a = new ByRef; $a->prop = 1; echo '原对象: ';var_dump($a);echo '<br><br>';
$b = clone $a;//本句替换成 $b=$a,结果也还是3,不过不会触发ByRef::__clone, prop不会中间变成2。本例研究的是克隆后,$b->prop引用不变 echo '原对象: ';var_dump($a);echo '<br>'; echo 'clone 对象: ';var_dump($b);echo '<br><br>'; $b->prop = 3; // $a->prop is now 3 $b->prop1 = 'oh,u move'; // b的prop1 改变了,a的prop1没变 echo '原对象: ';var_dump($a);echo '<br>'; echo 'clone 对象: ';var_dump($b);echo '<br><br>'; echo '原对象的引用prop: ';echo $a->prop;echo '<br>'; echo 'clone 对象的引用prop: ';echo $b->prop;
###################结果###################
原对象: object(ByRef)#6 (2) { ["prop"]=> &int(1) ["prop1"]=> string(15) "haha, i am here" }
原对象: object(ByRef)#6 (2) { ["prop"]=> &int(2) ["prop1"]=> string(15) "haha, i am here" } clone 对象: object(ByRef)#7 (2) { ["prop"]=> &int(2) ["prop1"]=> string(15) "haha, i am here" }
原对象: object(ByRef)#6 (2) { ["prop"]=> &int(3) ["prop1"]=> string(15) "haha, i am here" } clone 对象: object(ByRef)#7 (2) { ["prop"]=> &int(3) ["prop1"]=> string(9) "oh,u move" }
原对象的引用prop: 3 clone 对象的引用prop: 3
|