php面向对象中的__clone(转)
转自:http://blog.sina.com.cn/s/blog_54e38bdc0100xhm7.html
在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值,也就是说,A与B是两个独立的对象,但B的初始值是由A对象确定的。
在php语言中,用简单的赋值语句是不能满足这种需求的。要满足这种需求虽然有很多途径,但实现clone()方法是其中最简单,也是最高效的手段。
$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("原对象:\n");
var_dump($obj);
echo '<br><br><br>';
print("Cloned 对象:\n");
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