对象的值传递和引用传递
<?php
class C1{
var $p1 = 1;
}
//普通变量的值传递示例
$v1 =1 ;
$v2 = $v1;
$v1++;
echo "<br />v1 = $v1;v2 = $v2;"; //结果为v1 = 2;v2 = 1
//对象的值传递示例:
$o1 = new C1();
$o2 = $o1;
$o1->p1 = 2;
echo "<br />o1->p1={$o1->p1},o2->p1 = {$o2->p1}"; //o1->p1=2,o2->p1 = 2
//对象的引用类型传递:
$o3 = new C1();
$o4 = &$o3;
$o3->p1 = 2;
echo "<br />o3->p1={$o3->p1},o4->p1 = {$o4->p1}"; //o3->p1=2,o4->p1 = 2
?>
由上述例子中可见,对于对象传值,值传递方式和引用传递方式,对对象的数据的改变的结果是一样的。那它们的区别在哪?
我们要从对象的数据的存储方式来理解:
$o1 = new C1(); //创建一个对象o1,其存储结果如图:
这里,实际上,变量名$o1中,存储的数据只是一个“对象编号:#1”,这个对象编号才会指向对象数据new C1()。这个编号数据,我们是不能控制的,而是由系统内部分配的。
$o2 =$o1; //此处发生了值传递,而对象的值传递,实际上是发生复制对象编号,结果如图:
我们可以看到,变量
o2复制了
o1的“对象编号:#1”,它们的对象编号共同指向一个对象本身。此时:
o1->p1 =2; //通过“对象编号:#1”修改了对象(new C1() )本身的内部数据。
echoo2->p1; //取得了“对象编号:#1”所指向的对象(new C1() )本身的内部数据。所以它们的值是一样的。
$o3 = new C1(); //又创建了一个对象$o3,其存储结果如图:
$o4 = &$o3; //此处发生了引用传递,而对象的引用传递,实际上是发生指向同一个对象编号,结果如图:
$o3->p1 =2; //通过“对象编号:#2”修改了对象(new C1() )本身的内部数据。
echo $o4->p1; //取得了“对象编号:#2”所指向的对象(new C1() )本身的内部数据。所以它们的值是一样的。
对象的克隆(复制)
对象的克隆或复制,就是将目前已经存在的对象另外复制一份出来。类似于类的值传递,只不过克隆后,数据相同,对象编号不同。(当前相同,但此后一方的改变不会给另一方带来影响)
语法形式:
$obj2 = clone $obj1;
$obj2 = clone($obj1);
示例:
由于在克隆的时候,会将原有对象的属性,一模一样的复制一份。给我们带来的问题是,不能通过属性来区分哪个是原有对象,哪个是新对象。
解决方法是,对某些标识性的属性,进行修改即可。
方法一:
克隆完成后,手动修改属性。
方法二:
使用__clone()完成修改工作(推荐)。
__clone():双下划线开头,是PHP内部使用的方法。其特点是:当进行克隆的时候,PHP内部核心会自动使克隆的新对象使用该方法。
__clone()方法不是必须存在,当它存在时(被定义),就一定会被自动调用。
深克隆
如果某个对象的属性值为另一个对象的时候,那么在克隆该对象时:
当PHP为浅克隆时,仅仅克隆当前对象,而不克隆属性的对象。结果为,新老对象共用同一个属性对象。
结果:
两个英雄,共用一把武器!
如果需要将武器再次克隆,就要使用深克隆(由自己编程实现)。
通常利用__clone()方法。
在__clone()方法执行前,克隆时已经将新对象的武器属性克隆为其自己的武器属性值。