### **clone关键字**
**用于克隆一个完全一样的对象,克隆之后两个对象互不干扰。**
> 适用场景:在编码过程中,有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值,也就是说,A与B是两个独立的对象,但B的初始值是由A对象确定的。
```
// 使用clone关键字之前的复制效果实例
//
// 定义一个类,类中定义一个公共成员变量
class TestClass
{
public $value;
}
$obj = new TestClass(); // 实例化TestClass类的对象
$obj->value = 'qq'; // 给成员变量赋值
var_dump($obj); // object(TestClass)#228 (1) { ["value"]=> string(2) "qq" }
$obj2 = $obj; // 将$obj赋值给$obj2变量,等同于复制一个$obj
$obj2->value = 'zz'; // 更改$value的值
var_dump($obj); // object(TestClass)#228 (1) { ["value"]=> string(2) "zz" }
var_dump($obj2); // object(TestClass)#228 (1) { ["value"]=> string(2) "zz" }
```
从以上的例子可以看出来当实例化对象赋值给其他变量时,改变实例化对象和改变赋值对象,另一方都会随之改变。这是因为普象的赋值,仅仅是把新对象指向对象存储的地址(即 $obj给了$obj2它的地址,就和引用一样,$obj2指向了$obj,所以导致两者所执行的操作将会收到影响)。
```
// 使用clone关键字之后的复制效果实例
//
// 定义一个类,类中定义一个公共成员变量
class TestClass
{
public $value;
}
$obj = new TestClass(); // 实例化TestClass类的对象
$obj->value = 'qq'; // 给成员变量赋值
var_dump($obj); // object(TestClass)#228 (1) { ["value"]=> string(2) "qq" }
$obj2 = clone $obj; // 使用clone关键字克隆$obj
$obj2->value = 'zz'; // 更改$value的值
var_dump($obj); // object(TestClass)#228 (1) { ["value"]=> string(2) "qq" }
var_dump($obj2); // object(TestClass)#228 (1) { ["value"]=> string(2) "zz" }
```
可以看出,使用clone关键字之后,更改$obj2的成员变量值并不会对$obj的成员变量产生影响,克隆之后的两个对象$obj和$obj2是互不影响,互相独立的。
### **__clone方法**
**用于重写原本的属性和方法;__clone() 方法只会在对象被克隆的时候自动调用。**
> __clone()方法对一个对象实例进行的浅复制,对象内的基本数值类型进行的是传值复制,而对象内的对象型成员变量,如果不重写__clone方法,显式的clone这个对象成员变量的话,这个成员变量就是传引用复制,而不是生成一个新的对象。
```
// 定义age类
class Age
{
public $balance;
public function __construct($balance)
{
$this->balance = $balance;
}
}
//
// 定义第二个类,类中包括两个公共成员以及构造函数、克隆方法
class IndexService
{
public $age; // 对象属性成员变量
public $name; // 非对象属性成员变量
public function __construct($name, Age $age)
{
$this->name = $name;
$this->age = $age;
}
// 使用clone的时候触发
public function __clone()
{
$this->name = 'name:'.$this->name;
$this->age = clone $this->age; // 这个对象会被强制复制,这样就不会指向原来的对象。
}
}
// 运行
$obj = new IndexService('peter',new Age(20));
$obj2 = clone $obj;
$obj2->age->balance = 10;
var_dump($obj);
var_dump($obj2); // age对象中的balance值更改为10,name值也被更改。
```
![](https://img.kancloud.cn/02/dc/02dcaea6a562a59a69e4a01b3e9a638f_511x254.png)
> 注意: __clone()方法中的clone操作只能用于对象,如果用于非对象属性,将会报错:# 致命错误: __clone method called on non-object。
> 例子中的age就是一个对象。
以上例子中,$age对象被强制复制,不会指向原来的对象,所以修改其中的值之后,并不会对原来对象有影响;如果不加上`$this->age = clone $this->age;`这行代码,运行结果则变成这样:两个对象的age对象的balance值都改成了10。
![](https://img.kancloud.cn/90/70/90707a423336d80e3f668733f7cbe758_526x251.png)