谈谈拷贝这件小事

栏目: PHP · 发布时间: 6年前

内容简介:当在使用某个对象,而需要对该对象进行大量操作,或者在新的上下文环境中复用该对象的部分或全部数据时,需要对其进行拷贝操作。那么结合代码来看看从浅拷贝到深拷贝发生了什么上面创建了一个people类,然后实例化了p1,用赋值的方式 创建了p2 这样就得到了两个名字,年龄,性别都一样的人。那么当我们修改p1或p2时都会改变name

当在使用某个对象,而需要对该对象进行大量操作,或者在新的上下文环境中复用该对象的部分或全部数据时,需要对其进行拷贝操作。

拷贝的深浅

  • 我们日常所使用的拷贝,如一个文件夹,或者视频,音乐的拷贝,使用时可以发现这种拷贝是真正的生成了一个新的文件,占用了部分内存的。那么这种就是深拷贝,也就是在计算机中重新开辟了一块新的内存地址用于存放对象。 而什么是浅拷贝,浅拷贝只是拷贝了基本的数据类型,而引用数据类型,复制后也是会发生引用,浅拷贝只是指向被复制的内存地址。如果引用数据类型的对象发生了改变,那么浅拷贝出来的对象也会改变

由浅入深

那么结合代码来看看从浅拷贝到深拷贝发生了什么

<?php

class People {

    protected $_name = '张三';
    protected $_sex = '男';
    protected $_age = '18';

    /**
     * return Name
     */
    public function getName() {
        return $this-> _name;
    }
    /**
     * set name
     */
    public function setName($name) {
        $this->_name = (string)$name;
        return $this;
    }
}
$p1 = new People();
$p2 = $p1;
复制代码

上面创建了一个people类,然后实例化了p1,用赋值的方式 创建了p2 这样就得到了两个名字,年龄,性别都一样的人。那么当我们修改p1或p2时都会改变name

echo $p1->getName();
echo $p2->getName();
//p2改名
$p2->setName('李四');
echo $p1->getName();
echo $p2->getName();
//p1改名
$p1->setName('王五');
echo $p1->getName();
echo $p2->getName();
复制代码

输出为:张三张三李四李四王五王五

这里对象的赋值和传值都是以引用的方式。名字虽然不同但指的是同一个人。所以这种拷贝相当于一个人有个名字和外号,人还是这个人,这种拷贝不是我所想要的。那么换种方式。用clone来复制对象。

clone函数

$p1 = new People();
$p2 = clone $p1;
echo $p1->getName();
echo $p2->getName();
//p2改名
$p2->setName('李四');
echo $p1->getName();
echo $p2->getName();
//p1改名
$p1->setName('王五');
echo $p1->getName();
echo $p2->getName();
复制代码

那么这段代码用clone关键字复制p1对象,现在这个p1对象得到了这个真正的拷贝p2,p1和p2改名时分别都能改成功,而p1和p2都属于不同的对象,都是独立的个体了,如果p1有其他的关系,那么如何呢,就如同你克隆了一个人,尽管这个克隆人和本体的基本属性相同,但会有相同的记忆吗会有复杂的社会关系吗? 显然并不会

那么假如这个张三这个人有同学这个类,现在如何让克隆体也有这个同学类呢。下面精简一下代码

class People {

    public $name = '张三';
    public $mate;
    /**
     * 构造函数中加载同学对象
     */
    public function __construct()
    {
        $this->mate = new Classmate();
    }
}
/**
 * 同学类
 */
class Classmate {
    public $name ="王五";
}
$p1 = new People();
$p2 = clone $p1;
$p2 ->name = "ll";
echo $p1->name;
echo $p2->name;
$p2->mate->name = "ll";
echo $p1->mate->name;
复制代码

然后可以发现p2可以改名字也就是p2的普通属性实现了深拷贝 而mate对象属性中的名字也会改变,存在一定的问题

一般有两种解决方法:

1.重写clone函数

class People {

    public $name = '张三';
    public $mate;
    /**
     * 构造函数中加载同学对象
     */
    public function __construct()
    {
        $this->mate = new Classmate();
    }
    
    //重写clone函数
    public function __clone() {
        $this->mate = clone $this->mate;
    }
}
/**
 * 同学类
 */
class Classmate {
    public $name ="王五";
}
$p1 = new People();
$p2 = clone $p1;
$p2 ->name = "ll";
echo $p1->name;
echo $p2->name;
$p2->mate->name = "ll";
echo $p1->mate->name;//输出还是王五
复制代码

这样就可以解决了,但是如果classmate中有很多属性,或者people类要引入很多类,那么这样的重写clone函数就会变得很麻烦

2序列化和反序列化

这种方法不用修改函数比较简单

<?php

class People {

    public $name = '张三';
    public $mate;
    /**
     * 构造函数中加载同学对象
     */
    public function __construct()
    {
        $this->mate = new Classmate();
    }


}
/**
 * 同学类
 */
class Classmate {
    public $name ="王五";
}
$p1 = new People();
$p2 = serialize($p1);
$p2 = unserialize($p2);
$p2 ->name = "ll";

$p2->mate->name = "ll";

echo $p1->mate->name;

复制代码

还可以用json_encode之后再json_decode,实现赋值和法二一样 


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Automate This

Automate This

Christopher Steiner / Portfolio / 2013-8-9 / USD 25.95

"The rousing story of the last gasp of human agency and how today's best and brightest minds are endeavoring to put an end to it." It used to be that to diagnose an illness, interpret legal docume......一起来看看 《Automate This》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

在线进制转换器
在线进制转换器

各进制数互转换器

URL 编码/解码
URL 编码/解码

URL 编码/解码