最近在写代码的时候,碰到需要copy对象,在 php.net 看到这段话:

$copy_of_object = clone $object;
当对象被复制后,PHP 5 会对对象的所有属性执行一个浅复制(shallow copy)。所有的引用属性 仍然会是一个指向原来的变量的引用。

赋值

在PHP中, 对象间的赋值操作实际上是引用操作 (事实上,绝大部分的编程语言都是如此! 主要原因是内存及性能的问题)

$bob = new Boy(10);
$jack = $bob;
$jack->age++;

echo $jack->age;    // 11
echo $bob->age; // 11

浅克隆

其实 $bob 和 $jack 指针都是指向同一个内存区,所以,修改任意一个对象,另外一个对象也会随之变化。
如果我们不希望对象是 reference 方式的复制,这就需要用到 clone 关键字。

$school = new School();
$jack = new Boy(10);
$school->FirstGrade($jack);
$school2 = clone $school;
$jack->age++;

echo $school->firstGrader->age; // 11
echo $school2->firstGrader->age;    // 11, 克隆对象中的对象 (引用属性) 也被修改

如果想要对象中的属性完全复制(指克隆对象和源对象指向两个不同的内存区)

深克隆

class School
{
    public $grader;

    /**
     * @param $grader
     */
    public function grade($grader)
    {
        $this->grader = $grader;
    }

    public function __clone()
    {
        $this->grader = clone $this->grader;
    }
}
$school = new School();
$jack = new Boy(10);
$school->grade($jack);
$school2 = clone $school;
$jack->age++;

echo $school->grader->age;  // 11
echo $school2->grader->age; // 10   此时,克隆的对象未发生变化。

总结

浅克隆:变量类型为标量(int,string, bool, array)为值传递,对象类型为引用传递。
深克隆:所有元素或属性均完全复制,与源对象无关,也就是说所有对于新对象的修改都不会影响到源对象。

Tips

在PHP里,只需要 $cloneObject = unserialize(serialize($object)) 对源对象做 序列化->反序列化 的操作,便可以得到深克隆的对象。(会有性能损失和安全问题,下一章会说对象序列化的安全问题)