php如何复制一个对象,PHP中的对象复制及__clone() 函数
在PHP中, 对象间的赋值操作实际上是引用操作 (事实上,绝大部分的编程语言都是如此! 主要原因是内存及性能的问题) , 比如 :
[code lang=”php”]
class myclass {
public $data;
}
$obj1 = new myclass();
$obj1->data = "aaa";
$obj2 = $obj1;
$obj2->data ="bbb"; //$obj1->data的值也会变成"bbb"
[/code]
因为$obj1和$obj2都是指向同一个内存区的引用,所以修改任何一个对象都会同时修改另外一个对象。
在有些时候,我们其实不希望这种reference式的赋值方式, 我们希望能完全复制一个对象,这是侯就需要用到 Php中的clone (对象复制)。
[code lang=”php”]
class myclass {
public $data;
}
$obj1 = new myclass();
$obj1->data ="aaa";
$obj2 = clone $obj1;
$obj2->data ="bbb"; // $obj1->data的值仍然为"aaa"
[/code]
因为clone的方式实际上是对整个对象的内存区域进行了一次复制并用新的对象变量指向新的内存, 因此赋值后的对象和源对象相互之间是基本来说独立的。
什么? 基本独立?!这是什么意思? 因为PHP的object clone采用的是浅拷贝(shallow copy)的方法, 如果对象里的属性成员本身就是reference类型的,clone以后这些成员并没有被真正复制,仍然是引用的。 (事实上,其他大部分语言也是这样实现的, 如果你对C++的内存,拷贝,copy constructor等概念比较熟悉,就很容易理解这个概念), 下面是一个例子来说明:
[code lang=”php”]
class myClass{
public $data;
}
$sss ="aaa";
$obj1 = new myClass();
$obj1->data =&$sss; //注意,这里是个reference!
$obj2 = clone $obj1;
$obj2->data="bbb"; //这时,$obj1->data的值变成了"bbb" 而不是"aaa"!
var_dump($obj1);
var_dump($obj2);
[/code]
我们再举一个更实用的例子来说明一下PHP clone这种浅拷贝带来的后果:
[code lang=”php”]
class testClass
{
public $str_data;
public $obj_data;
}
$dateTimeObj = new DateTime("2014-07-05", new DateTimeZone("UTC"));
$obj1 = new testClass();
$obj1->str_data ="aaa";
$obj1->obj_data = $dateTimeObj;
$obj2 = clone $obj1;
var_dump($obj1); // str_data:"aaa" obj_data:"2014-07-05 00:00:00"
var_dump($obj2); // str_data:"aaa" obj_data:"2014-07-05 00:00:00"
$obj2->str_data ="bbb";
$obj2->obj_data->add(new DateInterval(‘P10D’)); //给$obj2->obj_date 的时间增加了10天
var_dump($obj1); // str_data:"aaa" obj_data:"2014-07-15 00:00:00" !!!!
var_dump($obj2); // str_data:"bbb" obj_data:"2014-07-15 00:00:00"
var_dump($dateTimeObj) // 2014-07-15 00:00:00"
[/code]
这一下可以更加清楚的看到问题了吧。 一般来讲,你用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概念上有些相似,但执行流程并不一样)
[code lang=”php”]
class testClass
{
public $str_data;
public $obj_data;
public function __clone() {
$this->obj_data = clone $this->obj_data;
}
$dateTimeObj = new DateTime("2014-07-05", new DateTimeZone("UTC"));
$obj1 = new testClass();
$obj1->str_data ="aaa";
$obj1->obj_data = $dateTimeObj;
$obj2 = clone $obj1;
var_dump($obj1); // str_data:"aaa" obj_data:"2014-07-05 00:00:00"
var_dump($obj2); // str_data:"aaa" obj_data:"2014-07-05 00:00:00"
$obj2->str_data ="bbb";
$obj2->obj_data->add(new DateInterval(‘P10D’));
var_dump($obj1); // str_data:"aaa" obj_data:"2014-07-05 00:00:00"
var_dump($obj2); // str_data:"aaa" obj_data:"2014-07-15 00:00:00"
var_dump($dateTimeObj); //"2014-07-05 00:00:00"
[/code]
关于 __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如何复制一个对象,PHP中的对象复制及__clone() 函数相关推荐
- java复制一个对象_Java中对象的复制
假如说你想复制一个简单变量.很简单: 1 int n = 5;2 int m = n; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short,float,doubl ...
- php中克隆对象,复制与克隆对象《 PHP 面向对象 》
在 PHP 里面,复制一个对象,其实就是去引用一个对象,如果你改变了复制的对象里的属性,原来被复制的对象也会改变.也就是这两个对象引用的其实是一个东西,改变了其中的一个,另一个也会跟着改变. 如果想真 ...
- c++中delete对象后 调用成员函数_C++类的特殊成员函数及default/delete特性
本文包含以下内容 1. C++的四类特殊成员函数介绍,重点介绍拷贝构造函数和拷贝复制运算符 2. C++11中的default/delete特性 本文内容侧重个人理解,深入理解其原理推荐https:/ ...
- C++中常对象与常成员函数以及this与成员函数的联系与区别
class A { }; /* 小记:对于const声明的对象,针对哪个变哪个不变得问题,实际上就是const后的整体不变 e.g.: const int *A; 或 int const *A; / ...
- 阵列函数 java_Java复制阵列– Java中的阵列复制
阵列函数 java Today we will look into different ways for java array copy. Java provides inbuilt methods ...
- html页面怎样禁止复制粘贴,javascript中如何禁止复制粘贴?
在javascript中可以使用oncopy事件和onpaste事件来实现禁止复制粘贴的功能.oncopy事件会在用户拷贝元素上内容时被触发:onpaste事件在用户向元素中粘贴文本时触发. java ...
- C++中常对象、常成员函数、常成员变量
用const修饰的类对象叫做常对象, 用const修饰的成员函数叫常成员函数, 用const修饰的成员变量叫常成员变量, 常对象: 型如: const <类名> <对象 ...
- js Javascript中调用对象内函数.(字符串函数名)
对象['methodName'](args): window.οnlοad=function(){ //函数名字符串 var methodsName='plus'var x = cal[methods ...
- Java中String对象存储
2019独角兽企业重金招聘Python工程师标准>>> String对象 String s = new String("xyz"):创建了两个对象一个是" ...
最新文章
- 核酸和CT同时用, 听谁的?——兼释一天新增一万多
- msm8937+android7.1系统播放某个MP4文件在data分区下创建ramdump并生成很多elf文件问题
- verilog中数组的定义_systemverilog中的数组操作
- c 将数字数组转成字符串_C+|用指针指向字符串字面量、字符数组及字符指针数组...
- Azure下通过Powreshell批量添加、删除VM终结点
- WCF标准绑定以及传输协议与编码格式
- linux进入文件夹后退,实验二Linux系统简单文件操作命令
- [C/C++标准库]_[0基础]_[优先队列priority_queue的使用]
- 物资申请php,危废企业申请经营许可证需满足的条件及申请程序
- 字节跳动年底再招 10000 人,前端工程师非常紧缺!
- shrink_page_list 函数分析
- php样式优美的错误提示框,弹出框美化 alert样式美化
- ssh 登录linux xsell 登录Linux 提示用户密钥登录怎么解决
- 详解EMC测试国标GB/T 17626
- 什么是http服务器
- 作为一名投资人,我经常会问创业者 8 个问题
- AQS中非公平锁的实现原理简介
- 微服务2——服务的注册,调用(Nacos服务注册中心+服务调用+调用负载均衡)sca-comsumersca-provider
- i7处理器好吗_英特尔酷睿i5处理器和i7有什么区别
- pixhawk飞控解锁方法
热门文章
- 【Python】 数字求和
- “Abp.AbpBootstrapper – System.MissingMethodException: Method not found: Void Abp.Configuration.Setti
- C#设计模式之18-备忘录模式
- python can i use return in wiht statement?
- 代码抽象_如何通过抽象使代码更具可读性
- springMVC发送邮件
- java代码题_精选20道Java代码笔试题
- 如何使用 Python 将图片变为字符的模样
- Ubuntu美化方案
- Zigbee网络架构+ZigBee的体系结构+理解zigbee节点的实现的案例+“51单片机” 和 “zigbee” 、 “cc2530芯片” 之间的关系+芯片cc2530