先来看下php对克隆的定义:
你可能会想复制一个新的对象,保持所有属性与原来的对象的属性相同, 但必须是一个新的对象(因为如果不是新的对象,那么一个对象中的改变就会影响到另一个对象)。还有一种情况: 如果对象A中保存着对象B的引用,当你复制对象A时,你想其中使用的对象不再是对象B而是B的一个副本,那么 你必须得到对象A的一个副本。
意思就是复制完以后的对象你所看到的属性神马的可能没有变化,但是却是一个新的对象了。根据这个定义来定义两个简单的类来看下效果:
class A{
public $name='小名';
public $age = 19;
}
$a = new A;
$b = clone $a; //这里是对$a的复制,复制对象的语法是$copy_of_object = clone $object;
$a->name = "小李";
var_dump($a);
echo "<br/>";
var_dump($b);
输出结果如下:
object(A)#1 (2) { ["name"]=> string(6) "小李" ["age"]=> int(19) }
object(A)#2 (2) { ["name"]=> string(6) "小名" ["age"]=> int(19) }
通过结果我们可以看出object(A)#1这个指的是打印$a所显示结果,而object(A)#2,虽然都是类A的对象,但是一个编号是1,一个编号是2,完全是两个类,而且当我复制完成后,改变其中一个对象的值,不会影响另外的一个对象的值。这种复制方式被称作为浅克隆。其实也就是通过一个关键字clone搞定的。不过如果想让复制后的对象和被复制的对象有所差别,可以使用魔术方法__clone()来完成。也就是在类里面加上一个方法(比如我想让复制后的对象年龄为20):public function __clone(){$this->age = 20;}
__clone()魔术方法会在 $b = clone $a; 的时候自动调用,复制对象A的时候同时改变了它的$age的值。
这种浅克隆只能将当前的属性进行克隆,但是如果当前的属性是对象的时候,浅克隆就满足不了我们的需求了,这时候就需要用到深克隆,所谓的深克隆就是对象属性如果为对象,则将其生成克隆副本。在__clone()的方法的基础上,将类型为对象的属性进行克隆。再其基础上更改如下:
class A{
public $name='小名';
public $age = 19;
public $obj; //这个属性类型为对象
public function __clone(){
$this->age = 20;
}
}
class B{
public $name = '酱油';
}
$a = new A;
$a->obj = new B; //这里是以B作为$obj的类的定义,将B实例化,对象保存在$a->obj
$b = clone $a; //这里是对$a的复制,复制对象的语法是$copy_of_object = clone $object;
$a->name = "小李";
var_dump($a);
echo "<br/>";
var_dump($b);
结果如下:
object(A)#1 (3) { ["name"]=> string(6) "小李" ["age"]=> int(19) ["obj"]=> object(B)#2 (1) { ["name"]=> string(6) "酱油" } }
object(A)#3 (3) { ["name"]=> string(6) "小名" ["age"]=> int(20) ["obj"]=> object(B)#2 (1) { ["name"]=> string(6) "酱油" } }
这里可以看到obj属性保存的对象明显是一个对象(都为object(B)#2)
但是如果我们想在复制的时候让$obj这个对象也重新复制成一个新的对象,那么这个时候只需要改动__clone()方法
public function __clone(){
$this->age = 20;
$this->obj = new $this->obj; //这里在clone $a 的时候,会自动调用__clone(),会将$obj所保存的对象也clone一个 副本
}
结果如下:
object(A)#1 (3) { ["name"]=> string(6) "小李" ["age"]=> int(19) ["obj"]=> object(B)#2 (1) { ["name"]=> string(6) "酱油" } }
object(A)#3 (3) { ["name"]=> string(6) "小名" ["age"]=> int(20) ["obj"]=> object(B)#4 (1) { ["name"]=> string(6) "酱油" } }
至此,对象的复制才算完成。