PHP 对象拷贝和 基础数据类型的拷贝不同

生活不止眼前的苟且,还有旧爱发来的请帖。

 

在php中 基础数据类型的拷贝就是值传递

$myData = 1;
$myTest = $myData;
$myTest = 2;

echo $myData.PHP_EOL;
echo $myTest.PHP_EOL;

结果:

 

 对 $myTest 进行重新赋值之后,不会影响$myData 的值,这就是值传递

 

但是针对类对象的话,就不一样了

$myData = new stdClass();
$myData->data = 'my data';

$myTest = $myData;
$myTest->data = 'my test';

print_r($myData);
print_r($myTest);

结果:

对 $myTest属性值的修改会污染 $myData 的属性值,这是新手在循环代码中做对象赋值时经常会犯的错误,而且迭代次数多了之后不易察觉,要避免这个问题。

 

那要怎么处理这样的问题呢

$myData = new stdClass();
$myData->data = 'my data';

// 用这个方法 clone 就能避免污染
$myTest = clone $myData;
$myTest->data = 'my test';

print_r($myData);
print_r($myTest);

结果:

  

结果显示是 myTest的修改没有污染到 MyData的属性,属性值的修改互不影响

但是真的是这样吗?

$myBase = new stdClass();
$myBase->num = 1;

$myData = new stdClass();
$myData->data = 'my data';
$myData->base = $myBase; 

// 用这个方法 clone 就能避免污染
$myTest = clone $myData;
$myTest->data = 'my test';
$myTest->base->num = 2;

print_r($myData);
print_r($myTest);

结果:

 

 看 num 属性还是被污染了,为什么会这样呢

分析:你会发现虽然通过 clone 拷贝的对象普通属性不再相互污染,但是嵌套的对象属性依然存在这个互相影响的问题,因此,我们把引用赋值和 clone 拷贝统统称之为「浅拷贝」,只有嵌套的对象属性也不相互污染的拷贝才是真正相互对立的「深拷贝」。要实现这种深拷贝,就要用到我们前面提到的 __clone 魔术方法。

class MyBase {
    public $num = 1;
}

class MyData
{
    public $data;

    /**
     * @var MyBase
     */
    public $base;

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

$myData = new MyData();
$myData->data = 'my data';
$myData->base = new MyBase(); 

$myTest = clone $myData;
$myTest->data = 'my test';
$myTest->base->num = 2;

print_r($myData);
print_r($myTest);

结果:

 

 

以上就是对应的 一些需要注意的地方

 

 

 

posted @ 2022-04-29 09:02  方达达  阅读(16)  评论(0编辑  收藏  举报