【PHP】对象的复制(拷贝)与__clone()方法
2018-06-22 04:55:56来源:未知 阅读 ()
参考链接:
1、php.net官网文档 - 对象复制
什么时候用到?摘自php.net:
在多数情况下,我们并不需要完全复制一个对象来获得其中属性。但有一个情况下确实需要:如果你有一个 GTK 窗口对象,该对象持有窗口相关的资源。你可能会想复制一个新的窗口,保持所有属性与原来的窗口相同,但必须是一个新的对象(因为如果不是新的对象,那么一个窗口中的改变就会影响到另一个窗口)。还有一种情况:如果对象 A 中保存着对象 B 的引用,当你复制对象 A 时,你想其中使用的对象不再是对象 B 而是 B 的一个副本,那么你必须得到对象 A 的一个副本。
尝试使用最简单的“=”
首先要明确的是:php的对象是以一个标识符来存储的,所以对对象的直接“赋值”行为相当于“传引用”
<?php function dump($var){ var_dump($var); echo "<br/>"; } class A{ private $a; protected $b; public $c; public function d(){ echo "A -> d"; } } $a1 = new A(); $a2 = $a1; $a3 = new A(); dump($a1); dump($a2); dump($a3);
输出的结果是:
object(A)#1 (3) { ["a":"A":private]=> NULL ["b":protected]=> NULL ["c"]=> NULL } object(A)#1 (3) { ["a":"A":private]=> NULL ["b":protected]=> NULL ["c"]=> NULL } object(A)#2 (3) { ["a":"A":private]=> NULL ["b":protected]=> NULL ["c"]=> NULL }
其中可以注意到,作为对象标识符的#n,显示$a1和$a2其实是指向同一个对象,而$a3是另一个对象
所以,如果需要拷贝一个相同且全新的对象,不能直接通过=来复制,否则改变了$a1->a就相当于修改了$a2->a。
浅拷贝
PHP5中,类中有个魔术方法__clone(),在配合clone关键字和对象使用的时候,会自动调用(如果没有显式定义,则调用空的方法)。
clone关键字的作用是,复制某一个对象形成一个对象的“浅拷贝”,然后赋值给新的对象,此时对象标识符不同了!
<?php function dump($var){ var_dump($var); echo "<br/>"; } class B{ public $d; } class A{ public $a; public $b; public function d(){ echo "A -> d"; } } $a1 = new A(); $a1->a = 123; // 这里对象属性的值是一个对象示例,其实就是存储了对象标识符。使用clone关键字生成的拷贝中的b属性仍然指向旧对象的b属性指向的对象,这是"浅拷贝"出现的问题。如果需要指向一个新的对象,必须"深拷贝" $a1->b = new B(); // PHP 5 only $a2 = clone $a1; dump($a1); dump($a2);
输出的结果是:
object(A)#1 (2) { ["a"]=> int(123) ["b"]=> object(B)#2 (1) { ["d"]=> NULL } } object(A)#3 (2) { ["a"]=> int(123) ["b"]=> object(B)#2 (1) { ["d"]=> NULL } }
可以看到,$a1和$a2明显是两个不同的对象(对象标识符不同了)。但是需要留意的一点是,"b"指向的对象标识符都是#2,证明这两个对象是相同的,这就是“浅拷贝”的“缺陷”——但有时候这两个对象确实需要相同,所以PHP的clone默认是“浅拷贝”。
为什么叫浅拷贝(shallow copy)?
因为在复制的时候,所有的属性都是“值传递”的,而上面的b属性存储的是对象标识符,所以相当于做了“引用传递”,这并不是完全的拷贝,所以称为“浅拷贝”。
深拷贝
上面讲到,使用clone关键字的时候,会自动调用旧对象的__clone()方法(然后返回拷贝的对象),所以只需要在对应的类中重写__clone()方法,使返回的对象中的“引用传递”的属性指向另一个新的对象。以下是例子(可以比较“浅拷贝”的例子,其实就多了重写__clone()的步骤):
<?php function dump($var){ var_dump($var); echo "<br/>"; } class B{ public $d; } class A{ public $a; public $b; public function d(){ echo "A -> d"; } public function __clone(){ // clone自己 $this->b = clone $this->b; } } $a1 = new A(); $a1->a = 123; // 这里对象属性的值是一个对象示例,其实就是存储了对象标识符。使用clone关键字生成的拷贝中的b属性仍然指向旧对象的b属性指向的对象,这是"浅拷贝"出现的问题。如果需要指向一个新的对象,必须"深拷贝" $a1->b = new B(); // PHP 5 only $a2 = clone $a1; dump($a1); dump($a2);
结果就不同了,注意b属性的对象标识符:
object(A)#1 (2) { ["a"]=> int(123) ["b"]=> object(B)#2 (1) { ["d"]=> NULL } } object(A)#3 (2) { ["a"]=> int(123) ["b"]=> object(B)#4 (1) { ["d"]=> NULL } }
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:微信app支付 ci框架做的
下一篇:PHP加密技术
- PHP写UltraEdit插件脚本实现方法 2020-03-29
- php 带逗号千位符数字的处理方法 2020-03-28
- PHP三元运算符的结合性介绍 2020-03-28
- PHP静态延迟绑定和普通静态效率的对比 2020-03-28
- 基于php流程控制语句和循环控制语句 2020-03-28
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash