开发者学堂课程【PHP 进阶教程-由浅入深掌握面向对象开发-第一阶段:对象克隆】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/711/detail/12674
对象克隆
内容介绍:
一、学习对象克隆
二、小结
一、学习对象克隆
接下来学习对象克隆。在人类自然圈里面,有一种技术叫克隆,比如克隆羊多利,它就是从本体产生另一个相似的本体,是一个独立的品种。
这节课将学习对象的克隆,也就是产生对象。本节的目标是:了解对象克隆的概念,掌握克隆魔术方法的意义。
1.概念
(1)克隆对象:clone 关键字,这是需要用到的关键字。即通过已有的对象复制一个新的同样的对象,但是两者之间是独立的,并非同一个对象。
①克隆对象与原来对象内容一致(这只是一种表象,当前一样,未来未必一样)
②克隆出来的对象是新对象
③对象克隆出来后会自动调用魔术方法 _clone (前提是这个方法已经定义,否则不会调用)
2.步骤
(1)定义类时需要考虑对象是否允许被克隆,以及考虑如果允许克隆后是否需要针对克隆的新对象做的操作,还有如果不允许克隆,就有以下:
①不允许克隆:可以私有化 clone (魔术方法(不允许外部克隆,所有的私有化克隆方法都不允许类的外部调用。使用者一般都是外部)
②允许克隆处理:在 clone() 方法中设定好克隆对象的处理
(2)实例化对象并保存到变量
(3)需要从已有对象克隆产生新对象(不是赋值)
(4)使用 clone 产生对象
3.示例
(1)克隆对象是通过 clone 关键字实现,即:clone 加上对象代表的变量。
比如说:
Class Saler{
#属性
public $count;
private $money;
}
这里定义了一个类。
#实例化
$s1 = new Saler()
$s1->count
这里实例化产生了一个对象,对里面的属性做了一个复制,复制是为了证明克隆出来的对象和现有状态是一致的,而不是原始对象。因此复制与否也不重要。
#克隆
$s2 = clone $s1
克隆,把 $s1 克隆变成 $s2。
(2)具体案例
如图:
输入 15.php ,然后写入以下代码:
<?php
#对象克隆
比如说:
Class Saler{
#属性
public $count;
private $money;
}
#实例化
$s1 = new Saler()
$s1->count
#克隆
$s2 = clone $s1
输入代码后,打印这两个对象,查看它们是否是同一个对象。
如图:
输入:var_dump($s1,$s2)
然后运行,如图:
可以看到,第一个 s1 的编号为1,第二个s2 等待编号为2,此时已经可以说明它们是两个对象了,也就是说存在两个对象,而且两个对象的内容是一样的。这里的 count 值为1,说明 s2 克隆的对象是 s1 到目前状态为止的所有状态,即前面做的操作都会被克隆。这就是对象克隆产生新对象。
(3)证明两个对象不同
证明两个对象不同,可以修改一其中个对象的值,然后看对另外一个对象的值是否有影响。
输入:
#修改
$s2->count = 2;
var_dump($s1,$s2)
如图:
对 $2进行修改,把它的 count 值从1改为2。
运行,如图:
可以看到,第一个依旧是1,而第二个已经从1变成2了,也就是说,修改一个对象并不会影响另外一个对象,这足以说明它们两个是完全不同的对象。
以上可以说明克隆出来的是新对象。
(4)对象在实例化的时候会自动调用存在的构造方法__construct(),同样的,在类的内部,PHP 允许定义一个__clone 也就是克隆的方法,在对象被克隆后,新克隆出来的对象会自动调用这个方法。
把证明的代码删除,然后输入:
<?php2
#对象克隆
class Saler{
#属性
public $count;
private $money;
#克隆魔术方法
public function __clone
echo __METHOD__;
#实例化
$s1 new Saler();
$s1->count = 1;
#克隆
$s2 cLone $s1;
加上一个克隆魔术方法,这个方法是系统自己定义的,先去证明它们被调用了,把克隆先注释,此时这个方法是不会被调用的,但是一旦把注释删除,
如图:
可以看到,此时克隆方法被调用了。以上就是克隆魔术方法。
(5)如何证明被克隆出来的对象是调用了原来的方法,还是原来的对象 s1 在调用?
①方法一
如图:
在克隆魔术方法中加入:var_dump($this);
刷新页面,如图:
可以看到,是对象 s2 调用了方法。
②方法二
如图:
修改对象,输入:$this->money = 10;然后输入:var_dump($s1,$s2);在外部打印这个对象而不是打印 this
刷新页面,如图:
可以看到,第一个是1,编号为1,count 为1,money 等于 NULL ,说明没有被修改。而第二个的 money 是10,说明当前内部修改的 this 是 s2 对象。
这就是克隆对象调用克隆方法的一个特点。
(6)如果不允许对象被克隆,可以将 __clone() 方法私有化,与构造方法一样不需要外部实例化,也不需要外部克隆。
如图:
把克隆私有化,即把 public 改为 private。同时忽略所有 var_dump($s1,$s2);的打印,给其注释。
刷新页面,如图:
可以看到,克隆出来的对象会马上调用方法,而这里不允许克隆,因此报错。
所以还需要把克隆注释,如图:
这些代码是不允许执行的。
重新刷新页面,如图:
由于不允许克隆,因此不会有对象克隆出来。这样从内部防止了外部克隆对象,这也是克隆的一个特点。
二、小结
1、对象可以通过克隆来得到新的对象
以前只有实例化才能产生新对象,现在克隆也可以产生新对象,
2、克隆出来的对象会自动调用类中对应的 __clone() 方法
如果没有方法,就不会调用,但是如果有,就一定会自动调用。
3、因为克隆对象是新对象,它不会改变原来的对象。
所以希望在当前对象达到某种临界点时候,需要复制但是后面可能还需要使用它,保留它的状态的时候使用克隆。如果需要一个和当前对象一致状态的对象,但是又不想改变当前对象的状态,那么就可以通过克隆来实现
4、可以通过私有化克隆方法来实现禁止外部对象克隆
因为每次对象进行克隆都是对内存的消耗,所以如果不需要或者不希望克隆的时候,可以通过私有化克隆方法来实现禁止外部对象克隆。如果这个类是给其他用户使用的,一般就需要这样操作,如果是自己使用,就无需这样操作。
以上就是对象的克隆。