个人博客网站文章地址:http://blog.mclink.xyz/index/article/index/id/36.html
很多新手PHPer对oop编程不熟的容易对这些概念忽视,最近在读初级PHP工程师这本书的时候对对象引用这一部分比较模糊,查了一些资料,理解了一下,想在此做一下记录,告诉自己这些基础一定要巩固好。
参考文章:https://blog.csdn.net/hel12he/article/details/49617023
https://blog.csdn.net/koastal/article/details/52163483
首先我们应该先明白PHP中内存空间是如何分布的。一般来说,内存空间分为堆内存,栈内存,数据段,代码段,如下图:
那么什么是对象的引用呢?
当我们使用new关键字对某个类进行实例化的时候,我们可以通过这个对象来访问该类中的属性以及方法。并且每个对象之间都是独立的,例如一个汽车类有着大小,颜色等属性,有行驶的方法,这个类可以被实例化成多个对象,每个对象的属性方法都可以修改,也就是说对象是有自己的内存空间的,它里面包含了实例该类的属性以及方法,对对象进行引用,或者说是使用别名,实际上指向的是同一个内存空间,例如:
<?php
class One
{
public $name;
public function __construct($name)
{
$this->name = $name;
}
}
//实例化,并且向构造函数传递参数
$o1 = new One('test1');
echo "对象1的name值为:".$o1->name."<br/>";
//引用
$o2 = $o1;
//打印对象2的$name属性
echo "对象2的name值为:".$o2->name."<br/>";
//修改对象$o2的$name属性
echo "修改对象2的name为test2"."<br/>";
$o2->name = 'test2';
//比较此时两个对象的$name值
echo "修改后对象1的name值为:".$o1->name."<br/>";
echo "修改后对象2的name值为:".$o2->name."<br/>";
打印结果:
由此可知,引用本质上只是只是对象的别名而已,实际上被引用对象和引用对象指向的内存空间还是一样的。(这里$o2=&o1的效果也是一样的)。
那么什么是浅复制呢?
概念:使用clone来复制对象,这种复制叫做“浅复制“,被赋值对象的所有变量都还有与原来对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。也就是说,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
我们使用相同的例子,把$o2=$o1改成$o2=clone $o1.看看会发生什么。打印结果如下图:
可以看到,当我们只修改对象2的值的时候,对象1的并没有发生改变,因为使用clone关键字是生成了一个对象的副本,这个副本也是有自己的内存空间的,它们之前相互独立。但是浅复制中是没有把它所引用的对象也复制下来。
前面说的东西都是内容只有数值的情况,当内容中也有引用的对象那就不一样了,也就引出了深复制的概念。
何为引用的对象呢?就是说可能类的成员变量存储的是另一个类的实例化对象,我们假设为对象3,那么这样的话,对象1和对象2的成员变量是共用对象3的。
深复制概念:被复制的对象的所有的变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。也就是说深复制把要复制的对象所引用的对象都复制了一遍。
两种方法:
①利用__clone魔术方法
public function __clone()
{
$this->obj = clone $this->obj;
}
②利用串行化
$t = serialize($o1);
$o2 = unserialize($t);
举个栗子:
<?php
header("Content-type:text/html;charset=utf-8");
class TvControl{
}
class Tv{
private $color;
private $tvControl;
function __construct(){
$this->color = "black";
$this->tvControl = new TvControl();
}
function getTvControl(){
return $this->tvControl;
}
}
$tv1 = new Tv();
$tvControl1 = $tv1->getTvControl();
echo "原始类:"."<br/>";
var_dump($tv1);
echo "<br/>";
$tv2 = $tv1;
echo "引用类:"."<br/>";
var_dump($tv2);
echo "<br/>";
$tv3 = clone $tv1;
echo "克隆(浅复制):"."<br/>";
var_dump($tv3);
echo "<br/>";
$tv4 = unserialize(serialize($tv1));
echo "深复制:"."<br/>";
var_dump($tv4);
打印结果:
深复制获取到的对象也是一个全新的对象。
那么如何比较两个对象是否引用于同一个对象呢?
我么可以使用“===”来进行比较两个对象是否引用于同一个初始对象。而“==”只能比较两个对象是否具有相同的类和属性。