国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

Home php教程 PHP源碼 php5 object copy, clone, shallow copy and deep copy

php5 object copy, clone, shallow copy and deep copy

Nov 08, 2016 pm 02:36 PM

The origin of object copying
Why objects have the concept of "copying"? This is closely related to the value transfer method of objects in PHP5. Let us take a look at the following simple code

PHP code

    * /** 
    * * 電視機類 
    * */ 
    * class Television   
    * {  
    *     /** 
    *      * 屏幕高度 
    *      */ 
    *     protected 
      $_screenLength = 300;  
    *       
    *     /** 
    *      * 屏幕寬度 
    *      */ 
    *     protected 
      $_screenHight  = 200;  
    *       
    *     /** 
    *      * 電視機外觀顏色 
    *      */ 
    *     protected 
      $_color        = 'black';  
    *       
    *     /** 
    *      * 返回電視外觀顏色 
    *      */ 
    *     public 
      function getColor()  
    *     {  
    *         return 
      $this->_color;  
    *     }  
    *       
    *     /** 
    *      * 設(shè)置電視機外觀顏色 
    *      */ 
    *     public 
      function setColor($color)  
    *     {  
    *         $this->_color = (string)$color;  
    *         return 
      $this;  
    *     }  
    * }  
    *   
    * $tv1 = new Television();  
    * $tv2 = $tv1;


This code defines a TV class Television, $tv1 is an instance of a TV, and then we assign the value of $tv1 to $t2 according to the ordinary variable assignment method. So now we have two TVs $tv1 and $tv2. Is this really the case? Let's test it out.

PHP code


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


First we see that the colors of tv1 and tv2 are both black. Now we want tv2 to change its color, so we set its color to white. Let’s look at the color of tv2 again. It did become white, which seemed to meet our requirements, but it was not as smooth as expected. When we looked at the color of tv1, we found that tv1 also changed from black to black. white. We did not reset the color of tv1. Why did tv1 change black to white? This is because the assignment and value transfer of objects in PHP5 are all done by "reference". PHP5 uses Zend Engine II, objects are stored in independent structures Object Store, instead of being stored in Zval like other general variables (in PHP4, objects are stored in Zval like general variables). Store only the pointer of the object in Zval and not the content (value). When we copy an object or pass an object as a parameter to a function, we do not need to copy the data. Just keep the same object pointer and notify the Object that this particular object now points to by another zval Store. Since the object itself is located in Object Store, any changes we make to it will affect all zval structures holding pointers to the object - reflected in the program, any changes to the target object will affect the source object. .this makes PHP objects appear to be always passed by reference. So the above tv2 and tv1 actually point to the same TV instance, and the operations we do on tv1 or tv2 are actually for this same instance. So our "copy" failed. It seems that the direct variable assignment method cannot copy the object. For this reason PHP5 provides an operation specifically for copying objects, which is clone. This is where object copying comes in.


Use clone to copy objects
We now use PHP5’s clone language structure to copy objects. The code is as follows:
[size=+0]PHP code

    * [size=+0]$tv1 = new Television();  
    * $tv2 = clone $tv1;  
    * 
    * echo 
      &#39;color of tv1 is: &#39; . $tv1->getColor();//tv1的顏色是black 
    * echo 
      &#39;<br>&#39;;  
    * echo 
      &#39;color of tv2 is: &#39; . $tv2->getColor();//tv2的顏色是black 
    * echo 
      &#39;<br>&#39;;  
    * 
    * //把tv2換成涂成白色 
    * $tv2->setColor(&#39;white&#39;);  
    * 
    * echo 
      &#39;color of tv2 is: &#39; . $tv2->getColor();//tv2的顏色是white 
    * echo 
      &#39;<br>&#39;;  
    * echo 
      &#39;color of tv1 is: &#39; . $tv1->getColor();//tv1的顏色是black


In line 2 of this code, we Use the clone keyword to copy tv1. Now we have a real copy of tv1, tv2. We still follow the previous method to check whether the copy is successful. We can see that we changed the color of tv2 to white, and the color of tv1 is still black, so our copy operation is successful.



__clone magic method

Now we consider the situation that each TV should have its own number. This number should be unique like our ID number, so when we copy a TV, we don’t want this The number is also copied to avoid causing some trouble. One strategy we came up with is to clear the assigned TV numbers, and then reassign the numbers as needed.
Then the __clone magic method is specifically used to solve such problems. The __clone magic method will be triggered when the object is copied (that is, the clone operation). We modified the code of the TV class Television and added the number attribute and __clone method. The code is as follows.
PHP code

    * /** 
    * * 電視機類 
    * */ 
    * class Television   
    * {  
    *       
    *     /** 
    *      * 電視機編號 
    *      */ 
    *     protected 
      $_identity    = 0;  
    *       
    *     /** 
    *      * 屏幕高度 
    *      */ 
    *     protected 
      $_screenLength = 300;  
    *       
    *     /** 
    *      * 屏幕寬度 
    *      */ 
    *     protected 
      $_screenHight  = 200;  
    *       
    *     /** 
    *      * 電視機外觀顏色 
    *      */ 
    *     protected 
      $_color        = &#39;black&#39;;  
    *       
    *     /** 
    *      * 返回電視外觀顏色 
    *      */ 
    *     public 
      function getColor()  
    *     {  
    *         return 
      $this->_color;  
    *     }  
    *       
    *     /** 
    *      * 設(shè)置電視機外觀顏色 
    *      */ 
    *     public 
      function setColor($color)  
    *     {  
    *         $this->_color = (string)$color;  
    *         return 
      $this;  
    *     }  
    *   
    *    /** 
    *      * 返回電視機編號 
    *      */ 
    *     public 
      function getIdentity()  
    *     {  
    *         return 
      $this->_identity;      
    *     }  
    *       
    *     /** 
    *      * 設(shè)置電視機編號 
    *      */ 
    *     public 
      function setIdentity($id)  
    *     {  
    *         $this->_identity = (int)$id;  
    *         return 
      $this;  
    *     }  
    *       
    *     public 
      function __clone()  
    *     {  
    *         $this->setIdentity(0);   
    *     }  
    * }


Let’s copy such a TV object.

PHP code

    * $tv1 = new Television();  
    * $tv1->setIdentity(&#39;111111&#39;);  
    * echo 
      &#39;id of tv1 is &#39; . $tv1->getIdentity();//111111  
    * echo 
      &#39;<br>&#39;;  
    *   
    * $tv2 = clone $tv1;  
    * echo 
      &#39;id of tv2 is &#39; . $tv2->getIdentity();//0


We produced a television tv1, And set its number to 111111, then we use clone to copy tv1 to tv2. At this time, the __clone magic method is triggered. This method will directly act on the copied object tv2. We called the setIdentity member in the __clone method. The method clears the _identity attribute of tv2 so that we can renumber it later. From this we can see that the __clone magic method allows us to do some additional operations very conveniently when cloning an object.

Fatal flaw of clone operation
Can clone really achieve the ideal copying effect? In some cases, you should find that the clone operation is not as perfect as we imagined. Let’s modify the above TV type and then do a test.
Every TV will come with a remote control, so we will have a remote control class. The remote control and the TV are an "aggregation" relationship (relative to the "combination" relationship, it is a weaker dependency relationship. Because generally TVs can be used normally even without a remote control), now our TV objects should all hold a reference to the remote control object. Let’s take a look at the code
PHP code

    * /** 
    * * 電視機類 
    * */ 
    * class Television   
    * {  
    *       
    *     /** 
    *      * 電視機編號 
    *      */ 
    *     protected 
      $_identity    = 0;  
    *       
    *     /** 
    *      * 屏幕高度 
    *      */ 
    *     protected 
      $_screenLength = 300;  
    *       
    *     /** 
    *      * 屏幕寬度 
    *      */ 
    *     protected 
      $_screenHight  = 200;  
    *       
    *     /** 
    *      * 電視機外觀顏色 
    *      */ 
    *     protected 
      $_color        = &#39;black&#39;;  
    *       
    *     /** 
    *      * 遙控器對象 
    *      */ 
    *     protected 
      $_control      = null;  
    *       
    *     /** 
    *      * 構(gòu)造函數(shù)中加載遙控器對象 
    *      */ 
    *     public 
      function __construct()  
    *     {  
    *         $this->setControl(new Telecontrol());  
    *     }  
    *   
    *     /** 
    *      * 設(shè)置遙控器對象 
    *      */ 
    *     public 
      function setControl(Telecontrol $control)  
    *     {  
    *         $this->_control = $control;  
    *         return 
      $this;  
    *     }  
    *       
    *     /** 
    *      * 返回遙控器對象 
    *      */ 
    *     public 
      function getControl()  
    *     {  
    *         return 
      $this->_control;  
    *     }      
    *       
    *     /** 
    *      * 返回電視外觀顏色 
    *      */ 
    *     public 
      function getColor()  
    *     {  
    *         return 
      $this->_color;  
    *     }  
    *       
    *     /** 
    *      * 設(shè)置電視機外觀顏色 
    *      */ 
    *     public 
      function setColor($color)  
    *     {  
    *         $this->_color = (string)$color;  
    *         return 
      $this;  
    *     }  
    *   
    *    /** 
    *      * 返回電視機編號 
    *      */ 
    *     public 
      function getIdentity()  
    *     {  
    *         return 
      $this->_identity;      
    *     }  
    *       
    *     /** 
    *      * 設(shè)置電視機編號 
    *      */ 
    *     public 
      function setIdentity($id)  
    *     {  
    *         $this->_identity = (int)$id;  
    *         return 
      $this;  
    *     }  
    *       
    *     public 
      function __clone()  
    *     {  
    *         $this->setIdentity(0);   
    *     }  
    * }  
    *   
    *   
    * /** 
    * * 遙控器類 
    * */ 
    * class Telecontrol   
    * {  
    *   
    * }


Copy such a TV object and observe the remote control object of the TV.

PHP code

    * $tv1 = new Television();  
    * $tv2 = clone $tv1;  
    *   
    * $contr1 = $tv1->getControl(); //獲取tv1的遙控器contr1 
    * $contr2 = $tv2->getControl(); //獲取tv2的遙控器contr2 
    * echo 
      $tv1;    //tv1的object id 為 #1 
    * echo 
      &#39;<br>&#39;;  
    * echo 
      $contr1; //contr1的object id 為#2 
    * echo 
      &#39;<br>&#39;;   
    * echo 
      $tv2;    //tv2的object id 為 #3 
    * echo 
      &#39;<br>&#39;;  
    * echo 
      $contr2; //contr2的object id 為#2

經(jīng)過復(fù)制之后,我們查看對象id,通過clone操作從tv1復(fù)制出了tv2,tv1和tv2的對象id分別是 1和3,這表示tv1和tv2是引用兩個不同的電視機對象,這符合clone操作的結(jié)果。然后我們分別獲取了tv1的遙控器對象contr1和tv2的遙控器對象contr2,通過查看它們的對象 id我們發(fā)現(xiàn)contr1和contr2的對象id都是2,這表明它們是到同一個對象的引用,也就是說我們雖然從tv1復(fù)制出tv2,但是遙控器并沒有被復(fù)制,每臺電視機都應(yīng)該配有一個遙控器,而這里tv2和tv1共用一個遙控器,這顯然是不合常理的。

由此可見,clone操作有這么一個非常大的缺陷:使用clone操作復(fù)制對象時,當被復(fù)制的對象有對其它對象的引用的時候,引用的對象將不會被復(fù)制。然而這種情況又非常的普遍,現(xiàn)今 “合成/聚合復(fù)用”多被提倡用來代替“繼承復(fù)用”,“合成”和“聚合”就是讓一個對象擁有對另一個對象的引用,從而復(fù)用被引用對象的方法。我們在使用 clone的時候應(yīng)該考慮到這樣的情況。那么在clone對象的時候我們應(yīng)該如何去解決這樣的一個缺陷呢?可能你很快就想到了之前提到的__clone魔術(shù)方法,這確實是一種解決方案。

方案1:用__clone魔術(shù)方法彌補
前面我們已經(jīng)介紹了__clone魔術(shù)方法的用法,我們可以在__clone方法中將被復(fù)制對象中其它對象的引用重新引用到一個新的對象。下面我們看看修改后的__clone()魔術(shù)方法:

[size=+0][size=+0]PHP代碼

    * [size=+0][size=+0]public 
      function __clone()  
    * {  
    *     $this->setIdentity(0);  
    *     //重新設(shè)置一個遙控器對象 
    *     $this->setControl(new Telecontrol());  
    * }


第04行中我們?yōu)閺?fù)制出來的電視機對象重新設(shè)置了一個遙控器,我們按照之前的方法查看對象的id可以發(fā)現(xiàn),兩臺電視機的遙控器擁有不同的對象id,這樣我們的問題就解決了。

但是這樣的方式大概并不算太好,如果被復(fù)制對象中有多個到其它對象的引用,我們必須在__clone方法中逐個的重新設(shè)置,更糟糕的是如果被復(fù)制對象的類由第三方提供,我們無法修改代碼,那復(fù)制操作基本就無法順利完成了。
我們使用clone來復(fù)制對象,這種復(fù)制叫做“淺復(fù)制”:被復(fù)制對象的所有變量都含有與原來的對象相同的值,而所有的對其他對象的引用都仍然指向原來的對象。也就是說,淺復(fù)制僅僅復(fù)制所考慮的對象,而不復(fù)制它所引用的對象。相對于“淺復(fù)制”,當然也有一個“深復(fù)制”:被復(fù)制的對象的所有的變量都含有與原來的對象相同的值,除去那些引用其他對象的變量。也就是說,深復(fù)制把要復(fù)制的對象所引用的對象都復(fù)制了一遍。深復(fù)制需要決定深入到多少層,這是一個不容易確定的問題,此外可能會出現(xiàn)循環(huán)引用的問題,這些都必須小心處理。我們的方案2將是一個深復(fù)制的解決方案。

方案2:利用串行化做深復(fù)制
PHP有串行化(serialize)和反串行化(unserialize)函數(shù),我們只需要用serialize()將一個對象寫入一個流,然后從流中讀回對象,那么對象就被復(fù)制了。在JAVA語言里面,這個過程叫做“冷藏”和“解凍”。下面我們將測試一下這個方法:
[size=+0][size=+0]PHP代碼

    * [size=+0][size=+0]$tv1 = new Television();  
    * $tv2 = unserialize(serialize($tv1));//序列化然后反序列化 
    * 
    * $contr1 = $tv1->getControl(); //獲取tv1的遙控器contr1 
    * $contr2 = $tv2->getControl(); //獲取tv2的遙控器contr2 
    * 
    * echo 
      $tv1;    //tv1的object id 為 #1 
    * echo 
      &#39;<br>&#39;;  
    * echo 
      $contr1; //contr1的object id 為#2 
    * echo 
      &#39;<br>&#39;;   
    * echo 
      $tv2;    //tv2的object id 為 #4 
    * echo 
      &#39;<br>&#39;;  
    * echo 
      $contr2; //contr2的object id 為#5

我們可以看到輸出結(jié)果,tv1和tv2擁有了不同的遙控器。這比方案1要方便很多,序列化是一個遞歸的過程,我們不需要理會被對象內(nèi)部引用了多少個對象以及引用了多少層對象,我們都可以徹底的復(fù)制。注意使用此方案時我們無法觸發(fā)__clone魔術(shù)方法來完成一些附加操作,當然我們可以在深復(fù)制之后再進行一次clone操作來觸發(fā)__clone魔術(shù)方法,只是會對效率些小的影響。另外此方案會觸發(fā)被復(fù)制對象和所有被引用對象的__sleep和__wakeup魔術(shù)方法,所以這些情況都需要被考慮。?



總結(jié)?
?? 不同的對象復(fù)制方式有著不同的效果,我們應(yīng)該根據(jù)具體應(yīng)用需求來考慮使用哪種方式以及如何改進復(fù)制方式。PHP5的面向?qū)ο筇匦院蚃AVA比較接近,相信我們可以從JAVA中借鑒很多寶貴的經(jīng)驗。

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undress AI Tool

Undress AI Tool

Undress images for free

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

PHP Tutorial
1502
276