对象复制

在多数情况下,我们并不需要完全复制一个对象来获得其中属性。但有一个情况下确实需要:如果第一个对象中保存着第二个对象的引用,当你复制第一个对象时,你想使用的对象不再是第二个对象而是它的一个副本,那么你必须得到第二个对象的一个副本。对象复制可以通过 clone 关键字来完成(如果可能,这将调用对象的 __clone() 方法)。对象中的 __clone() 方法不能被直接调用。当对象被复制后, PHP 会对对象的所有属性执行一个浅复制。所有的引用属性仍然会是一个指向原来的变量的引用。

<?php

class Cat
{
    /**
     * The name of cat.
     *
     * @var string
     */
    public string $name;

    /**
     * The age of cat.
     *
     * @var int
     */
    public int $age;

    /**
     * Store the name and age.
     *
     * @param  string $name
     * @param  int    $age
     * @return void
     */
    public function __construct(string $name, int $age)
    {
        $this->name = $name;
        $this->age = $age;
    }
}

class Dog
{
    /**
     * The name of dog.
     *
     * @var string
     */
    public string $name;

    /**
     * Store an instance of cat.
     *
     * @var Cat
     */
    public Cat $cat;
}

$spike = new Dog();
$spike->name = 'Spike';
$spike->cat = new Cat('Tom', 6);
$tyke = clone $spike;
var_dump($spike); // object(Dog)#1 (2) { ["name"]=> string(5) "Spike" ["cat"]=> object(Cat)#2 (2) { ["name"]=> string(3) "Tom" ["age"]=> int(6) } }
var_dump($tyke);  // object(Dog)#3 (2) { ["name"]=> string(5) "Spike" ["cat"]=> object(Cat)#2 (2) { ["name"]=> string(3) "Tom" ["age"]=> int(6) } }

$tyke->name = 'Tyke';
$tyke->cat->age = 2;
var_dump($spike); // object(Dog)#1 (2) { ["name"]=> string(5) "Spike" ["cat"]=> object(Cat)#2 (2) { ["name"]=> string(3) "Tom" ["age"]=> int(2) } }
var_dump($tyke);  // object(Dog)#3 (2) { ["name"]=> string(4) "Tyke" ["cat"]=> object(Cat)#2 (2) { ["name"]=> string(3) "Tom" ["age"]=> int(2) } }

当复制完成时,如果定义了 __clone() 方法,则新创建的对象(复制生成的对象)中的 __clone() 方法会被调用,可用于修改属性的值(如果有必要的话)。

<?php

class Cat
{
    /**
     * The name of cat.
     *
     * @var string
     */
    public string $name;

    /**
     * The age of cat.
     *
     * @var int
     */
    public int $age;

    /**
     * Store the name and age.
     *
     * @param  string $name
     * @param  int    $age
     * @return void
     */
    public function __construct(string $name, int $age)
    {
        $this->name = $name;
        $this->age = $age;
    }
}

class Dog
{
    /**
     * The name of dog.
     *
     * @var string
     */
    public string $name;

    /**
     * Store an instance of cat.
     *
     * @var Cat
     */
    public Cat $cat;

    /**
     * Complete deep copy.
     *
     * @param  void
     * @return void
     */
    public function __clone()
    {
        $this->cat = clone $this->cat;
    }
}

$spike = new Dog();
$spike->name = 'Spike';
$spike->cat = new Cat('Tom', 6);
$tyke = clone $spike;
var_dump($spike); // object(Dog)#1 (2) { ["name"]=> string(5) "Spike" ["cat"]=> object(Cat)#2 (2) { ["name"]=> string(3) "Tom" ["age"]=> int(6) } }
var_dump($tyke);  // object(Dog)#3 (2) { ["name"]=> string(5) "Spike" ["cat"]=> object(Cat)#4 (2) { ["name"]=> string(3) "Tom" ["age"]=> int(6) } }

$tyke->name = 'Tyke';
$tyke->cat->age = 2;
var_dump($spike); // object(Dog)#1 (2) { ["name"]=> string(5) "Spike" ["cat"]=> object(Cat)#2 (2) { ["name"]=> string(3) "Tom" ["age"]=> int(6) } }
var_dump($tyke);  // object(Dog)#3 (2) { ["name"]=> string(4) "Tyke" ["cat"]=> object(Cat)#4 (2) { ["name"]=> string(3) "Tom" ["age"]=> int(2) } }

可以将对象序列化后再反序列化来完成对象的深复制。

<?php

class Cat
{
    /**
     * The name of cat.
     *
     * @var string
     */
    public string $name;

    /**
     * The age of cat.
     *
     * @var int
     */
    public int $age;

    /**
     * Store the name and age.
     *
     * @param  string $name
     * @param  int    $age
     * @return void
     */
    public function __construct(string $name, int $age)
    {
        $this->name = $name;
        $this->age = $age;
    }
}

class Dog
{
    /**
     * The name of dog.
     *
     * @var string
     */
    public string $name;

    /**
     * Store an instance of cat.
     *
     * @var Cat
     */
    public Cat $cat;
}

$spike = new Dog();
$spike->name = 'Spike';
$spike->cat = new Cat('Tom', 6);
$tyke = unserialize(serialize($spike));
var_dump($spike); // object(Dog)#1 (2) { ["name"]=> string(5) "Spike" ["cat"]=> object(Cat)#2 (2) { ["name"]=> string(3) "Tom" ["age"]=> int(6) } }
var_dump($tyke);  // object(Dog)#3 (2) { ["name"]=> string(5) "Spike" ["cat"]=> object(Cat)#4 (2) { ["name"]=> string(3) "Tom" ["age"]=> int(6) } }

$tyke->name = 'Tyke';
$tyke->cat->age = 2;
var_dump($spike); // object(Dog)#1 (2) { ["name"]=> string(5) "Spike" ["cat"]=> object(Cat)#2 (2) { ["name"]=> string(3) "Tom" ["age"]=> int(6) } }
var_dump($tyke);  // object(Dog)#3 (2) { ["name"]=> string(4) "Tyke" ["cat"]=> object(Cat)#4 (2) { ["name"]=> string(3) "Tom" ["age"]=> int(2) } }

还可以将对象进行 JSON 编码后再解码来完成对象的深复制。

<?php

class Cat
{
    /**
     * The name of cat.
     *
     * @var string
     */
    public string $name;

    /**
     * The age of cat.
     *
     * @var int
     */
    public int $age;

    /**
     * Store the name and age.
     *
     * @param  string $name
     * @param  int    $age
     * @return void
     */
    public function __construct(string $name, int $age)
    {
        $this->name = $name;
        $this->age = $age;
    }
}

class Dog
{
    /**
     * The name of dog.
     *
     * @var string
     */
    public string $name;

    /**
     * Store an instance of cat.
     *
     * @var Cat
     */
    public Cat $cat;
}

$spike = new Dog();
$spike->name = 'Spike';
$spike->cat = new Cat('Tom', 6);
$tyke = json_decode(json_encode($spike));
var_dump($spike); // object(Dog)#1 (2) { ["name"]=> string(5) "Spike" ["cat"]=> object(Cat)#2 (2) { ["name"]=> string(3) "Tom" ["age"]=> int(6) } }
var_dump($tyke);  // object(stdClass)#3 (2) { ["name"]=> string(5) "Spike" ["cat"]=> object(stdClass)#4 (2) { ["name"]=> string(3) "Tom" ["age"]=> int(6) } }

$tyke->name = 'Tyke';
$tyke->cat->age = 2;
var_dump($spike); // object(Dog)#1 (2) { ["name"]=> string(5) "Spike" ["cat"]=> object(Cat)#2 (2) { ["name"]=> string(3) "Tom" ["age"]=> int(6) } }
var_dump($tyke);  // object(stdClass)#3 (2) { ["name"]=> string(4) "Tyke" ["cat"]=> object(stdClass)#4 (2) { ["name"]=> string(3) "Tom" ["age"]=> int(2) } }

results matching ""

    No results matching ""