对象复制
在多数情况下,我们并不需要完全复制一个对象来获得其中属性。但有一个情况下确实需要:如果第一个对象中保存着第二个对象的引用,当你复制第一个对象时,你想使用的对象不再是第二个对象而是它的一个副本,那么你必须得到第二个对象的一个副本。对象复制可以通过 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) } }