加入收藏 | 设为首页 | 会员中心 | 我要投稿 银川站长网 (https://www.0951zz.com/)- 云通信、基础存储、云上网络、机器学习、视觉智能!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

php中浅复制与深复制的示例

发布时间:2023-05-23 12:52:28 所属栏目:PHP教程 来源:
导读:前段时间头一次听说浅复制与深复制了,当时就是看的java例子,下文我来为各位分享一些小编总结的php中浅复制与深复制的例子供各位学习.周末闲来无事看到了原型模式,其中谈到了浅复制和深复制,想到PHP中的对应赋值、克隆

前段时间头一次听说浅复制与深复制了,当时就是看的java例子,下文我来为各位分享一些小编总结的php中浅复制与深复制的例子供各位学习.

周末闲来无事看到了原型模式,其中谈到了浅复制和深复制,想到PHP中的对应赋值、克隆以及克隆是浅复制还是深复制.

先来看看赋值,例如有一个简历类,有身高和体重两个属性:

class Resume  

    public $height; 

    public $weight; 

    public $workExperience; 

$ResumeA = new Resume(); 

$ResumeB = $ResumeA; 

此时实例化了一个Resume类并赋值给了$ResumeA变量,然后将$ResumeA变量赋值给$ResumeB,PHP手册上有说.

自PHP5起,new运算符自动返回一个引用,一个对象变量已经不再保存整个对象的值,只是保存一个标识符来访问真正的对象内容,当对象作为参数传递,作为结果返回,或者赋值给另外一个变量,另外一个变量跟原来的不是引用的关系,只是他们都保存着同一个标识符的拷贝,这个标识符指向同一个对象的真正内容.

所以若通过$ResumeB修改height属性,则$ResumeA也会跟着变,如果想要复制一个全新的对象,则可以通过clone来实现,如.

$ResumeB = clone $ResumeA;

此时将$ResumeA的值拷贝到新的变量$ResumeB中,改变其中一个不影响另一个,修改$ResumeB中height属性,$ResumeA不会跟着改变。

但如果该类引用了其他对象,则所有的引用仍然指向到原来的对象。clone的这种复制方式就是浅复制。被赋值对象的所有变量都还有与原来对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。

如果上面类中workExperience为WorkExperience类的引用,当克隆的时候,克隆前后的workExperience属性还是指向到同一个对象内容.

与浅复制对应的是深复制,深复制把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。

PHP中可以通过两种方式来实现深复制,第一种是__clone魔术方法:

public function __clone() 

    $this->workExperience = new WorkExperience(); 

深复制涉及深的层次,通过clone魔术方法实现需要知道有几层然后对每一层依次实现。还有一种是可以通过序列化对象的方式,先将对象序列化之后再反序列化,如:

$ResumeB = unserialize(serialize($ResumeA));

clone还算常用的拷贝方式,整理的目的只是为了记录一下clone是浅复制,需要注意一下对象的引用.

我们再举一个更实用的例子来说明一下PHP clone这种浅拷贝带来的后果:

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"  //开源软件:Cuoxin.com 

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" 

这一下可以更加清楚的看到问题了吧,一般来讲,你用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概念上有些相似,但执行流程并不一样).

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" //开源软件:Cuoxin.com 

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" 

关于 __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方法可以做很多事情,但我目前能想到的就只有把 浅拷贝变成深拷贝 这个场景的应用了,如果有其他用法,欢迎大家提出来.

(编辑:银川站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!