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

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索php
, 对象
, 变量
, new
属性
php 浅复制、成功不可复制例子、全民k歌评论复制例子、目光短浅的例子、浅尝辄止的例子,以便于您获取更多的相关知识。

时间: 2024-11-17 13:51:59

php中浅复制与深复制的例子的相关文章

深度解析javascript中的浅复制和深复制

     在谈javascript的浅复制和深复制之前,我们有必要在来讨论下js的数据类型.我们都知道有 Number,Boolean,String,Null,Undefined,Object五种类型.而Object又包含Function,Array 和Object自身.前面的五种类型叫做基本类型,而Object是引用类型.可能有人就要问,为什么要分基本类型和引用类型呢?后面你就会明白的.      我们首先来看看浅复制和深复制的简洁定义: 深复制:直接将数据复制给对应的变量 浅复制:将数据的地

举例区分Python中的浅复制与深复制

  这篇文章主要介绍了举例区分Python中的浅复制与深复制,是Python入门学习中的重要知识,需要的朋友可以参考下 copy模块用于对象的拷贝操作.该模块非常简单,只提供了两个主要的方法: copy.copy 与 copy.deepcopy ,分别表示浅复制与深复制.什么是浅复制,什么是深复制,网上有一卡车一卡车的资料,这里不作详细介绍.复制操作只对复合对象有效.用简单的例子来分别介绍这两个方法. 浅复制只复制对象本身,没有复制该对象所引用的对象. ? 1 2 3 4 5 6 7 8 9 1

java中对象的浅复制和深复制笔记

在面向对象的语言中,如Java/Python,对象的复制有两种形式:浅复制和深复制 一.浅复制    浅复制只是将原对象的引用备份了一份给新的变量,实际两者指向的是同一个对象.在Python中,字典.列表.元祖等都是对象类型 >>> person=['name',['savings',100.00]] >>> hubby=person[:] >>> wifely=list(person) >>> [id(x) for x in per

android 浅复制和深复制-clone篇

有关java中的 浅复制和深复制 ,这里不详细讨论.相关知识请参考以下帖子: 浅复制和深复制http://blog.csdn.net/yang_hui1986527/article/details/7029777 浅析Java中的深拷贝与浅拷贝http://blog.csdn.net/yang_hui1986527/article/details/7012428 android中的 浅复制和深复制,具体可能于java中的有一点不同.下面,我们来探讨下在这个问题. 主要思路: 1.创建TextBo

java 浅复制和深复制

原文:http://ttitfly.iteye.com/blog/155422 1.java里的clone分为:  A:浅复制(浅克隆): 浅复制仅仅复制所考虑的对象,而不复制它所引用的对象.  b:深复制(深克隆):深复制把要复制的对象所引用的对象都复制了一遍.  Java中对象的克隆,为了获取对象的一份拷贝,我们可以利用Object类的clone()方法.必须要遵循下面三点  1.在派生类中覆盖基类的clone()方法,并声明为public[Object类中的clone()方法为protec

android 浅复制和深复制-Java Generic Deep Copy 篇

关于Java Generic Deep Copy 在java中的应用和注意事项,请参考:http://blog.csdn.net/yang_hui1986527/article/details/7039425 而关于在android程序中通过clone方法来进行浅复制和深复制,请参考:http://blog.csdn.net/yang_hui1986527/article/details/7036818 众所周知,android上层使用的是java语言,因此理论上于Java Generic De

浅析:对象的浅复制和深复制

问题描述 在面向对象的语言中,如Java/Python,对象的复制有两种形式:浅复制和深复制一.浅复制浅复制只是将原对象的引用备份了一份给新的变量,实际两者指向的是同一个对象.在Python中,字典.列表.元祖等都是对象类型>>> person=['name',]>>> hubby=person>>> wifely=list(person)>>> >>>person是一个列表对象,分割之后赋给hubby,将perso

Java中对象的深复制和浅复制详解

1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. ⑵深复制(深克隆) 被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量.那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象.换言之,深复制把要复制的对象所引用的对象都复制了一遍. 2.Java的clone()方法 ⑴clone方法将对象复制了一份并返回

Java中的深拷贝(深复制)和浅拷贝(浅复制)介绍_java

深拷贝(深复制)和浅拷贝(浅复制)是两个比较通用的概念,尤其在C++语言中,若不弄懂,则会在delete的时候出问题,但是我们在这幸好用的是Java.虽然java自动管理对象的回收,但对于深拷贝(深复制)和浅拷贝(浅复制),我们还是要给予足够的重视,因为有时这两个概念往往会给我们带来不小的困惑. 浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象.深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象.举例来说更加清楚:对象A1中包含对B1的引用