PHP对象克隆clone用法示例:浅克隆与深克隆的区别
PHP 对象克隆使用 clone 关键字,默认行为为浅克隆。若对象包含其他对象属性,浅克隆会导致新旧对象共享同一子对象引用。要实现深克隆(Deep Clone),需在被克隆类中定义 __clone() 魔术方法,在其中对嵌套对象再次执行 clone,从而确保所有层级数据彻底独立。
浅克隆:默认行为与局限性
在 PHP 中,直接使用 clone $obj 进行对象克隆时,系统默认执行的是浅克隆(Shallow Copy)。这意味着:
- 标量类型(如 int, string, float 等)的值会被完整复制。
- 对象类型的属性仅仅复制其引用地址,新旧对象的该属性指向同一个对象实例。
- 资源类型(Resource)通常无法通过 clone 有效隔离,需谨慎处理。
这种机制下,如果修改新对象中的嵌套对象属性,原对象也会随之改变,因为它们共享同一个内部对象。
第1步:准备包含嵌套对象的类结构
首先定义两个类 B 和 A,其中 A 包含一个类型为 B 的属性 $b。
<?php
class B {
public $val = 10;
}
class A {
public $val = 20;
public $b;
public function __construct() {
$this->b = new B();
}
}
第2步:执行浅克隆并验证独立性
创建对象 A 的实例,克隆为新实例,然后分别修改两者的属性,观察 var_dump 输出结果。
<?php
$obj_a = new A();
$obj_b = clone $obj_a; // 浅克隆
// 修改原对象属性
$obj_a->val = 30;
$obj_a->b->val = 40; // 修改嵌套对象
var_dump($obj_a);
echo '<br>';
var_dump($obj_b);
第3步:分析浅克隆运行结果
运行上述代码,输出如下:
object(A)[1]
public 'val' => int 30
public 'b' =>
object(B)[2]
public 'val' => int 40
object(A)[3]
public 'val' => int 20
public 'b' =>
object(B)[2]
public 'val' => int 40
关键观察:
$obj_a的val变为 30,$obj_b保持 20,说明标量值已独立复制。- 两者内部的
b属性对应的对象 ID 均为 [2]。这意味着它们指向内存中的同一个B对象实例。因此,修改$obj_a->b->val后,$obj_b->b->val也变成了 40。
深克隆:通过 __clone 实现完全独立
当需要确保对象及其所有嵌套子对象都完全独立时,必须实现深克隆。这需要在被克隆的类中定义 __clone() 魔术方法。该方法会在 clone 操作完成后自动触发。
第1步:在类中添加 __clone 方法
在类 A 中添加 __clone 方法,手动对嵌套的对象属性再次执行 clone 操作。
<?php
class B {
public $val = 10;
}
class A {
public $val = 20;
public $b;
public function __construct() {
$this->b = new B();
}
// 实现深克隆逻辑
public function __clone() {
// 对嵌套对象再次克隆,生成新的实例
$this->b = clone $this->b;
}
}
第2步:测试深克隆效果
重复之前的测试步骤,创建新实例并修改属性。
<?php
$obj_a = new A();
$obj_b = clone $obj_a; // 触发 __clone 方法
$obj_a->val = 30;
$obj_a->b->val = 40;
var_dump($obj_a);
echo '<br>';
var_dump($obj_b);
第3步:分析深克隆运行结果
运行结果如下:
object(A)[1]
public 'val' => int 30
public 'b' =>
object(B)[2]
public 'val' => int 40
object(A)[3]
public 'val' => int 20
public 'b' =>
object(B)[4]
public 'val' => int 10
关键观察:
$obj_b的val保持 20,$obj_b->b->val保持初始值 10。- 注意
$obj_b->b的对象 ID 变为了 [4],而$obj_a->b是 [2]。 - 这表明
$obj_b拥有了一个全新的B对象副本,与$obj_a的内部状态完全隔离,互不影响。
总结与注意事项
- 浅克隆适用场景:当嵌套对象是不可变的,或者业务逻辑允许共享子对象状态时,使用默认的浅克隆更高效简单。
- 深克隆适用场景:当对象作为配置项、缓存数据或需要严格状态隔离时,必须使用深克隆以避免副作用。
- 递归复杂度:如果对象结构非常复杂且存在循环引用,简单的递归
__clone可能不够,需借助工具库或序列化/反序列化方式处理(但需注意资源类型无法序列化)。 - 性能考量:深克隆涉及多次内存分配和数据复制,对于大型对象树,性能损耗高于浅克隆,应根据实际需求权衡。
以上就是 PHP 对象 clone 浅克隆和深克隆用法的详细内容,更多关于 PHP 面向对象程序设计入门教程的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









