前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于PHP中对象复制的那点事儿

关于PHP中对象复制的那点事儿

作者头像
硬核项目经理
发布2020-03-26 15:36:28
6350
发布2020-03-26 15:36:28
举报

关于PHP中对象复制的那点事儿

我们已经在PHP设计模式之原型模式中讨论过关于PHP中对象复制的问题,这次就当做是一次复习。

原型模式可以看作是对象复制中的一个重要内容。在学习原型模式时,我们了解到对象中的引用变量,也就是变量也是一个对象时,直接复制这个对象会导致其中的引用变量还是指向同一个对象。是不是有点绕,我们还是用例子来说明:

// clone方法
class testA{
    public $testValue;
}
class A
{
    public static $reference = 0;
    public $instanceReference = 0;
    public $t;

    public function __construct()
    {
        $this->instanceReference = ++self::$reference;
        $this->t = new testA();

    }

    public function __clone()
    {
        $this->instanceReference = ++self::$reference;
        $this->t = new testA();
    }
}

$a1 = new A();
$a2 = new A();
$a11 = clone $a1;
$a22 = $a2;

var_dump($a11); // $instanceReference, 3
var_dump($a22); // $instanceReference, 2

$a1->t->testValue = '现在是a1';
echo $a11->t->testValue, PHP_EOL; // ''


$a2->t->testValue = '现在是a2';
echo $a22->t->testValue, PHP_EOL; // 现在是a2
$a22->t->testValue = '现在是a22';
echo $a2->t->testValue, PHP_EOL; // 现在是a22

// 使用clone后
$a22 = clone $a2;
var_dump($a22); // $instanceReference, 4

$a2->t->testValue = '现在是a2';
echo $a22->t->testValue, PHP_EOL; // NULL
$a22->t->testValue = '现在是a22';
echo $a2->t->testValue, PHP_EOL; // 现在是a2

首先,通过变量的变化,我们可以看出使用clone关键字的对象复制会调用__clone()方法。这个魔术方法正在原型模式的核心所在。在这个方法中,我们可以重新实例化或者定义对象中的引用成员。通过clone,我们让变量重新实例化,从而让t成为了新的对象,从而避免引用带来的问题。

在对象的复制中,我们需要特别注意的递归引用的问题。也就是对象内部引用了自身,将会导致来回的重复引用形成递归死循环。

// 循环引用问题
class B
{
    public $that;

    function __clone()
    {
        // Segmentation fault: 11
        $this->that = clone $this->that;
        // $this->that = unserialize(serialize($this->that));
        // object(B)#6 (1) {
        //     ["that"]=>
        //     object(B)#7 (1) {
        //       ["that"]=>
        //       object(B)#8 (1) {
        //         ["that"]=>
        //         *RECURSION*  无限递归
        //       }
        //     }
        //   }
    }
}

$b1 = new B();
$b2 = new B();
$b1->that = $b2;
$b2->that = $b1;

$b3 = clone $b1;

var_dump($b3);

B类中的that指向自身的实例,两个对象相互指向后再进行复制,就会出现这种死循环的情况。使用序列化和反序列化输出后,我们会看到RECURSION的引用提示。这就是形成了递归的死循环。这种情况一定要极力避免。

上述例子中,我们使用了序列化和反序列化这一招来解决引用问题。对象复制的对象变量来说(对象变量里面还有更多层次的引用变量),这种方式能够一次性地在最顶层的对象__clone()方法中解决引用问题。

测试代码:https://github.com/zhangyue0503/dev-blog/blob/master/php/202001/source/%E5%85%B3%E4%BA%8EPHP%E4%B8%AD%E5%AF%B9%E8%B1%A1%E5%A4%8D%E5%88%B6%E7%9A%84%E9%82%A3%E7%82%B9%E4%BA%8B%E5%84%BF.php

参考文档:https://www.php.net/manual/zh/language.oop5.cloning.php

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-03-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码农老张 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 关于PHP中对象复制的那点事儿
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档