如何理解PHP中的对象引用,浅复制以及深复制

很多新手PHPer对oop编程不熟的容易对这些概念忽视,最近在读初级PHP工程师这本书的时候对对象引用这一部分比较模糊,查了一些资料,理解了一下,想在此做一下记录,告诉自己这些基础一定要巩固好。

参考文章:https://blog.csdn.net/hel12he/article/details/49617023

                  https://blog.csdn.net/koastal/article/details/52163483

  首先我们应该先明白PHP中内存空间是如何分布的。一般来说,内存空间分为堆内存,栈内存,数据段,代码段,如下图:

20180408144520886.png

那么什么是对象的引用呢?

   当我们使用new关键字对某个类进行实例化的时候,我们可以通过这个对象来访问该类中的属性以及方法。并且每个对象之间都是独立的,例如一个汽车类有着大小,颜色等属性,有行驶的方法,这个类可以被实例化成多个对象,每个对象的属性方法都可以修改,也就是说对象是有自己的内存空间的,它里面包含了实例该类的属性以及方法,对对象进行引用,或者说是使用别名,实际上指向的是同一个内存空间,例如:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

<?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的效果也是一样的)。

20180408164337622.png

那么什么是浅复制呢?

  概念:使用clone来复制对象,这种复制叫做“浅复制“,被赋值对象的所有变量都还有与原来对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。也就是说,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。

我们使用相同的例子,把$o2=$o1改成$o2=clone $o1.看看会发生什么。打印结果如下图:

20180408153438893.png

  可以看到,当我们只修改对象2的值的时候,对象1的并没有发生改变,因为使用clone关键字是生成了一个对象的副本,这个副本也是有自己的内存空间的,它们之前相互独立。但是浅复制中是没有把它所引用的对象也复制下来。

20180408164440984.png

前面说的东西都是内容只有数值的情况,当内容中也有引用的对象那就不一样了,也就引出了深复制的概念。

深复制概念:被复制的对象的所有的变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。也就是说深复制把要复制的对象所引用的对象都复制了一遍。

两种方法:

①利用__clone魔术方法

1

2

3

4

public function __clone()  

{  

    $this->obj = new Obj();  

}

②利用串行化

1

2

$t = serialize($o1);  

$o2 = unserialize($t);

举个栗子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

<?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);

打印结果:

20180408163352546.png

深复制获取到的对象也是一个全新的对象。

那么如何比较两个对象是否引用于同一个对象呢?

  我么可以使用“===”来进行比较两个对象是否引用于同一个初始对象。而“==”只能比较两个对象是否具有相同的类和属性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值