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);
结果:
以上就是对应的 一些需要注意的地方