php中clone语法使用详解

clone的作用是对象复制,但在使用过程中会遇到一些问题,下面我们针对这些问题探讨一番。


语法:

$cloneObject = clone $object;

1.在php中,我们把一个对象赋值给一个变量,实际上是把这个对象的引用赋给变量,他们指向的是同一个对象。当使用这个变量对对象进行操作时,实际上会影响所有指向这个对象的变量。

<?php

class TestA
{
    public $testPro;
}

$testA = new TestA();
$testData = $testA;

$testA->testPro = 'original value';
$testData->testPro = 'change value';

var_dump($testA->testPro);
var_dump($testData->testPro);

//结果:
//string(12) "change value" 
//string(12) "change value" 

在示例中,我们可以看到把$testA赋值给$testData,实际上是把指向testA对象的引用赋给了$testData。直观的表现是,当我们改变$testData->testPro的值时,$testA->testPro的值随之改变。

2.而php给我们提供了复制一个对象的方法,使用clone时,会在内存中重新开辟一个空间存放新的对象,变量指向这个新的空间地址。

<?php

class TestA
{
    public $testPro;
}

$testA = new TestA();
$testData = clone $testA;

$testA->testPro = 'original value';
$testData->testPro = 'change value';

var_dump($testA->testPro);
var_dump($testData->testPro);

//结果:
//string(14) "original value"
//string(12) "change value" 

在示例中,我们可以看到把$testA clone的副本赋值给$testData,实际上是复制一份新的testA对象放到一个新的内存空间,把这个新的内存空间的地址赋给$testData。直观的表现是,当我们改变$testData->testPro的值时,$testA->testPro的值随不改变。

3.但是,clone复制的新对象中的引用属性仍然指向旧对象该属性指向的地址。即所有的引用属性仍然会是一个指向原来变量的引用。

<?php

class TestA
{
    public $testPro;
}

class TestB
{
    public $testA;
}

$testA = new TestA();

$testA->testPro = 'original value';

$testB = new TestB();
$testB->testA = $testA;
$testB->testA->testPro = 'testB change value';

$cloneTestB = clone $testB;
$cloneTestB->testA->testPro = 'cloneTestB change value';

var_dump($cloneTestB->testA->testPro);
var_dump($testB->testA->testPro);
var_dump($testA->testPro);
//结果:
//string(23) "cloneTestB change value" 
//string(23) "cloneTestB change value" 
//string(23) "cloneTestB change value"

在示例中,我们可以看到cloneTestB 对象中的属性testA仍然和testB 对象中的属性testA指向的是同一个对象testA(直观的表现就是改变$cloneTestB->testA->testPro的值,$testB->testA->testPro和$testA->testPro的值随之改变)。

4.那么,如何解决3中的问题呢?我们可以在__clone()魔术方法中强制把testA属性指向一个经过clone得到的新的testA对象。

<?php

class TestA
{
    public $testPro;
}

class TestB
{
    public $testA;

    public function __clone()
    {
        $this->testA = clone $this->testA;
    }
}

$testA = new TestA();

$testA->testPro = 'original value';

$testB = new TestB();
$testB->testA = $testA;
$testB->testA->testPro = 'testB change value';

$cloneTestB = clone $testB;
$cloneTestB->testA->testPro = 'cloneTestB change value';

var_dump($cloneTestB->testA->testPro);
var_dump($testB->testA->testPro);
var_dump($testA->testPro);

//结果:
//string(23) "cloneTestB change value"
//string(18) "testB change value"
//string(18) "testB change value" 

在示例中,我们重载了TestB类的__clone魔术方法,在该方法中,我们把testA的值修改为原值的一个clone复制。这样经过clone得到的新对象的testA属性指向的地址和旧对象testA属性指向的地址就不同了。直观的表现是我们改变$cloneTestB->testA->testPro的值时,$testB->testA->testPro和$testA->testPro的值不再随之改变。

5.需要注意的是,我们在使用单例模式时,clone会给我们带来问题,具体的解决方法请参考:http://mp.blog.csdn.net/mdeditor/79388562

GitHub源码

参考文献:
http://php.net/manual/zh/language.oop5.cloning.php
https://www.cnblogs.com/maodouzi/archive/2010/06/15/1758502.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值