关于PHP中的对象(类的实例)的复制、clone(克隆)

来源:互联网 发布:ubuntu删除桌面文件夹 编辑:程序博客网 时间:2024/06/01 07:26

对象复制的由来
为什么对象会有“复制”这个概念,这与PHP5中对象的传值方式是密切相关的,让我们看看下面这段简单的代码

 /**  * 电视机类  **/      class Television        {           //屏幕高度           protected $_screenLength = 300;           //屏幕宽度          protected $_screenHight  = 200;            //电视机外观颜色         protected $_color = 'black';           //返回电视外观颜色         public function getColor()         {               return $this->_color;           }           //设置电视机外观颜色         public function setColor($color)           {               $this->_color = (string)$color;         }       }       $tv1 = new Television();//实例化电视机类     $tv2 = $tv1;//直接的对象复制

这段代码定义了一个电视机的类 Television , tv1tv1的值赋给t2tv1和$tv2了,真的是这样的吗?我们来测试一下。

echo 'color of tv1 is: ' . $tv1->getColor();//tv1的颜色是black echo '<br>';  echo 'color of tv2 is: ' . $tv2->getColor();//tv2的颜色是black echo '<br>';//把tv2涂成白色 $tv2->setColor('white');  echo 'color of tv2 is: ' . $tv2->getColor();//tv2的颜色是white echo '<br>';  echo 'color of tv1 is: ' . $tv1->getColor();//tv1的颜色是white 

首先我们看到tv1和tv2的颜色都是black,现在我们希望tv2换个颜色,所以我们将它的颜色设置成了white,我们再看看tv2的颜色,确实成为了white,似乎满足了我们的要求,可是并没有想象中的那么顺利,当我们接着看tv1的颜色的时候,我们发现tv1也由black边成了 white。我们并没有重新设置tv1的颜色,为什么tv1会重black变成white呢?

这是因为PHP5中对象的赋值和传值都是以“引用”的方式,把一个类的对象直接复制给另一个对象的时候,实质上这两个对象指向的是同一片内存中,该其中一个对象的属性或方法时另一个对象的属性和方法也会随之改变,复制“失败”了。

因此我们不能单纯的用变量赋值的方法复制一个对象。此 PHP5提供了一个专门用于复制对象的操作,也就是 clone 。这就是对象复制的由来。

用clone(克隆)来复制对象
我们现在使用PHP5的clone语言结构来复制对象,代码如下:

$tv1 = new Television();$tv2 = clone $tv1;echo 'color of tv1 is: ' . $tv1->getColor();//tv1的颜色是blackecho '<br>';  echo 'color of tv2 is: ' . $tv2->getColor();//tv2的颜色是black echo '<br>'; //把tv2换成涂成白色 $tv2->setColor('white');echo 'color of tv2 is: ' . $tv2->getColor();//tv2的颜色是whiteecho '<br>';echo 'color of tv1 is: ' . $tv1->getColor();//tv1的颜色是black 

这段代码的第2行,我们用clone关键字复制tv1,现在我们就拥有了一份真正的tv1的拷贝tv2,我们还是按照之前的方法来检测复制是否成功。我们可以看到,我们将tv2的颜色换成了white,tv1的颜色还是black,这样我们的复制操作就成功了。

__clone魔术方法

现在我们考虑到这样一个情况,每一台电视机应该都有自己的编号,这个编号如同我们的身份证号码一样应该是唯一的,所以当我们在复制一台电视机的时候,我们不希望这个编号也被复制过来,以免造成一些麻烦。我们想到的一个策略是将赋值出来的电视机的编号清空,然后再按照需求来重新分配编号。

那么__clone魔术方法就是专门用来解决这样的问题,__clone魔术方法会在对象被复制( 也就是clone操作)的时候被触发。我们修改了电视机类Television的代码,添加了编号属性和__clone方法,代码如下。
PHP代码

/**  * 电视机类  **/     class Television       {          //电视机编号        protected $_identity  = 0;          //屏幕高度          protected $_screenLength = 300;          //屏幕宽度         protected $_screenHight  = 200;           //电视机外观颜色        protected $_color = 'black';          //返回电视外观颜色        public function getColor()        {              return $this->_color;          }       //设置电视机外观颜色        public function setColor($color)          {              $this->_color = (string)$color;        }         //返回电视机编号        public function getIdentity()         {             return $this->_identity;             }          //设置电视机编号       public function setIdentity($id)        {            $this->_identity = (int)$id;        }       //使用__clone魔法方法      public function __clone()        {            $this->setIdentity(0);         }    }  

下面我们来复制这样的一个电视机对象。

$tv1 = new Television();$tv1->setIdentity('111111');echo 'id of tv1 is ' . $tv1->getIdentity();//111111echo '<br>';$tv2 = clone $tv1;//把$tv1克隆给$tv2echo 'id of tv2 is ' . $tv2->getIdentity();//0 

我们生产了一台电视机tv1 , 并且设置它的编号为111111,然后我们用clone将tv1复制得到了tv2,这个时候__clone魔术方法被触发,此方法将直接作用与复制得到的对象tv2,我们在__clone方法中调用了setIdentity成员方法将tv2的_identity属性清空,以便我们后面对它进行重新编号。由此我们可以看到__clone魔术方法能让我们非常方便的在clone对象的时候做一些附加的操作。

0 0
原创粉丝点击