PHP中的对象复制及__clone() 函数
来源:互联网 发布:六年级数学出题软件 编辑:程序博客网 时间:2024/05/20 05:55
http://www.androiddev.net/php-object-clone-copy-constructor/
在PHP中, 对象间的赋值操作实际上是引用操作 (事实上,绝大部分的编程语言都是如此! 主要原因是内存及性能的问题) , 比如 :
1
class
myclass {
2
public
$data
;
3
}
4
$obj1
=
new
myclass();
5
$obj1
->data =
"aaa"
;
6
$obj2
=
$obj1
;
7
$obj2
->data =
"bbb"
;
//$obj1->data的值也会变成"bbb"
因为$obj1和$obj2都是指向同一个内存区的引用,所以修改任何一个对象都会同时修改另外一个对象。
在有些时候,我们其实不希望这种reference式的赋值方式, 我们希望能完全复制一个对象,这是侯就需要用到 Php中的clone (对象复制)。
1
class
myclass {
2
public
$data
;
3
}
4
$obj1
=
new
myclass();
5
$obj1
->data =
"aaa"
;
6
$obj2
= clone
$obj1
;
7
$obj2
->data =
"bbb"
;
// $obj1->data的值仍然为"aaa"
因为clone的方式实际上是对整个对象的内存区域进行了一次复制并用新的对象变量指向新的内存, 因此赋值后的对象和源对象相互之间是基本来说独立的。
什么? 基本独立?!这是什么意思? 因为PHP的object clone采用的是浅拷贝(shallow copy)的方法, 如果对象里的属性成员本身就是reference类型的,clone以后这些成员并没有被真正复制,仍然是引用的。 (事实上,其他大部分语言也是这样实现的, 如果你对C++的内存,拷贝,copy constructor等概念比较熟悉,就很容易理解这个概念), 下面是一个例子来说明:
1
class
myClass{
2
public
$data
;
3
}
4
5
$sss
=
"aaa"
;
6
$obj1
=
new
myClass();
7
$obj1
->data =&
$sss
;
//注意,这里是个reference!
8
$obj2
= clone
$obj1
;
9
$obj2
->data=
"bbb"
;
//这时,$obj1->data的值变成了"bbb" 而不是"aaa"!
10
11
var_dump(
$obj1
);
12
var_dump(
$obj2
);
我们再举一个更实用的例子来说明一下PHP clone这种浅拷贝带来的后果:
1
class
testClass
2
{
3
public
$str_data
;
4
public
$obj_data
;
5
}
6
7
$dateTimeObj
=
new
DateTime(
"2014-07-05"
,
new
DateTimeZone(
"UTC"
));
8
9
$obj1
=
new
testClass();
10
$obj1
->str_data =
"aaa"
;
11
$obj1
->obj_data =
$dateTimeObj
;
12
13
$obj2
= clone
$obj1
;
14
15
var_dump(
$obj1
);
// str_data:"aaa" obj_data:"2014-07-05 00:00:00"
16
var_dump(
$obj2
);
// str_data:"aaa" obj_data:"2014-07-05 00:00:00"
17
18
$obj2
->str_data =
"bbb"
;
19
$obj2
->obj_data->add(
new
DateInterval(
'P10D'
));
//给$obj2->obj_date 的时间增加了10天
20
21
var_dump(
$obj1
);
// str_data:"aaa" obj_data:"2014-07-15 00:00:00" !!!!
22
var_dump(
$obj2
);
// str_data:"bbb" obj_data:"2014-07-15 00:00:00"
23
var_dump(
$dateTimeObj
)
// 2014-07-15 00:00:00"
这一下可以更加清楚的看到问题了吧。 一般来讲,你用clone来复制对象,希望是把两个对象彻底分开,不希望他们之间有任何关联, 但由于clone的shallow copy的特性, 有时候会出现非你期望的结果,上面的例子中,
1) $obj1->obj_data =$dateTimeObj 这句话实际上是个引用类型的赋值. 还记得前面提到的PHP中对象直接的赋值是引用操作么?除非你用$obj1->obj_dat = clone $dataTimeObj!
2) $obj2 = clone $obj1 这句话生成了一个obj1对象的浅拷贝对象,并赋给obj2. 由于是浅拷贝,obj2中的obj_data也是对$dateTimeObj的引用!
3)$dateTimeObj, $obj1->obj_data, $obj2->obj_data 实际上是同一个内存区对象数据的引用,因此修改其中任何一个都会影响其他两个!
如何解决这个问题呢? 采用PHP中的 __clone方法 把浅拷贝转换为深拷贝(这个方法给C++中的copy constructor概念上有些相似,但执行流程并不一样)
1
class
testClass
2
{
3
public
$str_data
;
4
public
$obj_data
;
5
6
public
function
__clone() {
7
$this
->obj_data = clone
$this
->obj_data;
8
}
9
10
$dateTimeObj
=
new
DateTime(
"2014-07-05"
,
new
DateTimeZone(
"UTC"
));
11
12
$obj1
=
new
testClass();
13
$obj1
->str_data =
"aaa"
;
14
$obj1
->obj_data =
$dateTimeObj
;
15
16
$obj2
= clone
$obj1
;
17
var_dump(
$obj1
);
// str_data:"aaa" obj_data:"2014-07-05 00:00:00"
18
var_dump(
$obj2
);
// str_data:"aaa" obj_data:"2014-07-05 00:00:00"
19
$obj2
->str_data =
"bbb"
;
20
$obj2
->obj_data->add(
new
DateInterval(
'P10D'
));
21
22
var_dump(
$obj1
);
// str_data:"aaa" obj_data:"2014-07-05 00:00:00"
23
var_dump(
$obj2
);
// str_data:"aaa" obj_data:"2014-07-15 00:00:00"
24
var_dump(
$dateTimeObj
);
//"2014-07-05 00:00:00"
关于 __clone() , PHP官方的文档: Once the cloing is complete, if a __clone() method is defined, then the newly created object’s __clone() method will be called, to allow any necessary properties that need to be changed.
按照这个定义,事实上__clone方法可以做很多事情,但我目前能想到的就只有把 浅拷贝变成深拷贝 这个场景的应用了, 如果有其他用法,欢迎大家提出来。
- PHP中的对象复制及__clone() 函数
- php clone __clone()复制
- php之clone 复制对象以及__clone魔术方法
- php 类 __clone 函数
- PHP面向对象编程中的魔术方法__clone()
- PHP对象克隆:__clone()方法
- Php面向对象--使用__clone()克隆对象
- php面向对象(OOP)—__toString()和__clone()
- 克隆对象__clone()方法
- php 5 clone __clone()
- php中的对象引用和复制
- PHP面向对象_对象克隆clone和魔术方法__clone()
- __clone()
- php面向对象基本概念(魔法方法)__invoke() __toString() __call() __callStatic() __clone()
- PHP的对象复制
- 78. PHP 对象复制
- php 对象复制
- php之对象复制
- 推开HTML5的大门
- 数据结构——桶式排序
- 改变cell的imageview的大小
- 虚拟化——影子页表
- css 绘制不规则不多边形实践及各方向>箭头(可兼容到ie8)
- PHP中的对象复制及__clone() 函数
- 在CentOS中部署Python和配置PyCharm开发环境
- 问题记录
- iOS去掉按钮的点击效果
- [SCOI2010]游戏
- php5.6开启curl支持
- 2016 JAVA与Android面试题整理
- 关于堆排序
- iOS自定义日历控件