PHP5 object replication, clone, shallow copy, and deep copy

Source: Internet
Author: User
Tags getcolor
The origin of object replication
Why do objects have the concept of "copy", which is closely related to the way objects are transmitted in PHP5, let's take a look at this simple piece of code

PHP Code

* /**
* * TV class
* */
* Class Television
* {
* /**
* * Screen height
* */
* Protected
$_screenlength = +;
*
* /**
* * Screen width
* */
* Protected
$_screenhight = $;
*
* /**
* * TV appearance color
* */
* Protected
$_color = ' black ';
*
* /**
* * Return to TV appearance color
* */
* Public
function GetColor ()
* {
* Return
$this->_color;
* }
*
* /**
* * Set the TV appearance color
* */
* Public
function SetColor ($color)
* {
* $this->_color = (string) $color;
* Return
$this;
* }
* }
*
* $TV 1 = new Television ();
* $TV 2 = $TV 1;


This code defines a TV class television, $TV 1 as an instance of a television set, and we assign the value of $TV1 to $t2 as a normal variable assignment. So now we have two TVs $TV1 and $TV2, is that really the case? Let's test it out.

PHP Code

* Echo
' Color of TV1 is: '. $tv 1->getcolor ();//TV1 's color is black.
* Echo
'
';
* Echo
' Color of TV2 is: '. $tv 2->getcolor ();//tv2 's color is black.
* Echo
'
';
*
*//Paint the TV2 white
* $tv 2->setcolor (' White ');
*
* Echo
' Color of TV2 is: '. $tv 2->getcolor ();//tv2 's white.
* Echo
'
';
* Echo
' Color of TV1 is: '. $tv 1->getcolor ();//TV1 's white.


First we see TV1 and TV2 color are black, now we want to TV2 change color, so we will its color set to white, we look at TV2 color, indeed become white, seems to meet our requirements, but not as well as imagined, As we went on to look at the color of the TV1, we found that TV1 also became white by the black side. We didn't reset the color of TV1, why did TV1 turn black into white? This is because the assignments and values of the objects in the PHP5 are referred to as "references." PHP5 uses Zend Engine II, objects are stored in a separate structure object store, not stored in zval like other general variables (stored in Zval as objects in PHP4 and general variables). Only pointers to objects, not content (value), are stored in zval. 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 be notified by another zval now that this particular object is pointing to the object Store. Since the object itself is in object Store, any changes we make to it will affect all zval structures that hold the pointer to the object----in the program that any change to the target object will affect the source object: This makes the PHP object look like always by reference (reference ) to pass. So the above TV2 and TV1 is actually pointing to the same TV example, we do the TV1 or TV2 the operation is actually for this same instance. So our "copy" failed. It seems that the direct variable assignment does not copy the object, so PHP5 provides an operation specifically for copying the object, which is clone. This is the origin of object replication.


copy objects with Clone (clone)
We are now using the clone language structure of PHP5 to copy the object with the following code:
[size=+0]php Code

* [size=+0] $TV 1 = new Television ();
* $TV 2 = clone $tv 1;
*

* Echo
' Color of TV1 is: '. $tv 1->getcolor ();//TV1 's color is black.
* Echo
'
';
* Echo
' Color of TV2 is: '. $tv 2->getcolor ();//tv2 's color is black.
* Echo
'
';
*

*//Replace the TV2 with painted white
* $tv 2->setcolor (' White ');
*

* Echo
' Color of TV2 is: '. $tv 2->getcolor ();//tv2 's white.
* Echo
'
';
* Echo
' Color of TV1 is: '. $tv 1->getcolor ();//TV1 's color is black.


In line 2nd of this code, we copied TV1 with the Clone keyword, and now we have a copy of the real TV1 TV2, and we'll follow the previous method to detect if the replication was successful. We can see that we replaced the TV2 color with the WHITE,TV1 color or black, so our copy operation was successful.



__clone Magic Method

Now that we think about it, every TV set should have its own number, and this number should be the same as our ID number, so when we're copying a TV set, we don't want this number to be duplicated, to avoid causing some trouble. One of the strategies we came up with was to empty the number of assigned TV sets, and then reassign the numbers as needed.
then the __clone Magic method is specifically designed to solve such problems, the __clone magic method will be triggered when the object is copied (that is, the clone operation). We have modified the code of the TV class television, added the numbering attribute and the __clone method, the code is as follows.
PHP Code

* /**
* * TV class
* */
* Class Television
* {
*
* /**
* * TV number
* */
* Protected
$_identity = 0;
*
* /**
* * Screen height
* */
* Protected
$_screenlength = +;
*
* /**
* * Screen width
* */
* Protected
$_screenhight = $;
*
* /**
* * TV appearance color
* */
* Protected
$_color = ' black ';
*
* /**
* * Return to TV appearance color
* */
* Public
function GetColor ()
* {
* Return
$this->_color;
* }
*
* /**
* * Set the TV appearance color
* */
* Public
function SetColor ($color)
* {
* $this->_color = (string) $color;
* Return
$this;
* }
*
* /**
* * Return TV number
* */
* Public
function getidentity ()
* {
* Return
$this->_identity;
* }
*
* /**
* * Set the TV number
* */
* 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

* $TV 1 = new Television ();
* $tv 1->setidentity (' 111111 ');
* Echo
' ID of TV1 is '. $tv 1->getidentity ();//111111
* Echo
'
';
*
* $TV 2 = clone $tv 1;
* Echo
' ID of TV2 is '. $tv 2->getidentity ();//0


we produced a TV TV1, and set its number is 111111, and then we use clone to copy the TV1 to get TV2, this time __clone magic method is triggered, this method will directly function with the copied object TV2, we are in __ The Setidentity member method is called in the Clone method to empty the _identity property of TV2 so that we can renumber it later. From this we can see that the __clone magic method can make it very convenient for us to do some additional operations on the Clone object.

fatal flaw in clone operation
can clone really achieve the desired copy effect? In some cases, you should find that the clone operation is not as perfect as we thought. We will modify the above TV class, and then do the test.
Each TV will come with a remote control, so we will have a remote control class, remote control and TV is a "aggregation" relationship (relative and "combination" relationship, is a weak dependency, because the general situation of the TV can be used without remote control), Now our TV objects should all hold a reference to the remote control object. Here's a look at the code
PHP Code

* /**
* * TV class
* */
* Class Television
* {
*
* /**
* * TV number
* */
* Protected
$_identity = 0;
*
* /**
* * Screen height
* */
* Protected
$_screenlength = +;
*
* /**
* * Screen width
* */
* Protected
$_screenhight = $;
*
* /**
* * TV appearance color
* */
* Protected
$_color = ' black ';
*
* /**
* * Remote object
* */
* Protected
$_control = null;
*
* /**
* * constructor to load the remote control object
* */
* Public
function __construct ()
* {
* $this->setcontrol (new Telecontrol ());
* }
*
* /**
* * Set remote Control object
* */
* Public
function Setcontrol (Telecontrol $control)
* {
* $this->_control = $control;
* Return
$this;
* }
*
* /**
* * Return to remote Control object
* */
* Public
function GetControl ()
* {
* Return
$this->_control;
* }
*
* /**
* * Return to TV appearance color
* */
* Public
function GetColor ()
* {
* Return
$this->_color;
* }
*
* /**
* * Set the TV appearance color
* */
* Public
function SetColor ($color)
* {
* $this->_color = (string) $color;
* Return
$this;
* }
*
* /**
* * Return TV number
* */
* Public
function getidentity ()
* {
* Return
$this->_identity;
* }
*
* /**
* * Set the TV number
* */
* Public
function setidentity ($id)
* {
* $this->_identity = (int) $id;
* Return
$this;
* }
*
* Public
function __clone ()
* {
* $this->setidentity (0);
* }
* }
*
*
* /**
* * Remote control class
* */
* Class Telecontrol
* {
*
* }


copy such a TV object below and observe the remote control object of the TV.

PHP Code

* $TV 1 = new Television ();
* $TV 2 = clone $tv 1;
*
* $contr 1 = $tv 1->getcontrol ();//Get TV1 remote control CONTR1
* $contr 2 = $tv 2->getcontrol ();//Get TV2 remote control CONTR2
* Echo
$TV 1; The object ID of//TV1 is #1
* Echo
'
';
* Echo
$contr 1;//contr1 's object ID is # #
* Echo
'
';
* Echo
$TV 2; The object ID of//TV2 is #3
* Echo
'
';
* Echo
$contr 2;//contr2 's Object ID is # #


after copying, we look at the object ID, the object IDs of TV2,TV1 and TV2 are copied from TV1 through the clone operation, respectively, 1 and 3, which means that TV1 and TV2 refer to two different TV objects, which are consistent with the result of the clone operation. We then acquired the TV1 remote object CONTR1 and TV2 's remote control object CONTR2, and by looking at their object ID we found that both CONTR1 and Contr2 object IDs are 2, which indicates that they are references to the same object. In other words, although we copied from the TV1 TV2, but the remote control has not been copied, each TV should be equipped with a remote control, and here TV2 and TV1 shared a remote control, which is obviously unreasonable.

Thus, there is a very large flaw in the clone operation: When copying an object using the clone operation, the referenced object will not be copied when the copied object has references to other objects. However, this is a very common situation, and nowadays "synthesis/aggregation multiplexing" is often advocated instead of "Inheritance multiplexing", "compositing" and "aggregation", which means that one object has a reference to another object, thus reusing the method of the referenced object. We should take this into account when using clone. So what should we do to solve such a flaw in the Clone object? You may soon think of the __clone magic method mentioned earlier, which is really a solution.

Scenario 1: Use __clone Magic method to compensate
we have already described the use of the __clone magic method, in which we can re-reference the references of other objects in the copied object to a new object in the __clone method. Let's look at the modified __clone () Magic method:

[size=+0][size=+0]php Code

* [Size=+0][size=+0]public
function __clone ()
* {
* $this->setidentity (0);
*//Reset a remote control object
* $this->setcontrol (new Telecontrol ());
* }


in line No. 04 we re-set a remote control for the copied TV object, we can see the ID of the object according to the previous method, we find that the remote control of the two TVs have different object IDs, so our problem is solved.

but this is probably not a very good way, if there are multiple references to other objects in the copied object, we must re-set in the __clone method, and worse, if the class of the copied object is provided by a third party, we cannot modify the code, the copy operation will not be completed successfully.
we use clone to copy the object, which is called "Shallow copy": All the variables of the copied object contain the same value as the original object, and all references to other objects still point to the original object. That is, a shallow copy simply duplicates the object being considered, not the object it refers to. There is, of course, a "deep copy" with respect to "shallow copy": All variables of the copied object contain the same value as the original object, except for those variables that refer to other objects. In other words, a deep copy copies the objects referenced by the object being copied over. Deep replication needs to decide how many layers to drill into, which is a problem that is not easily identified, and there may be problems with circular references, which must be handled with care. Our solution 2 will be a deep replication solution.

Scenario 2: Using serialization to do deep replication
PHP has serialization (serialize) and crossdress (unserialize) functions, and we only need to write an object to a stream with serialize () and then read the object back from the stream, then the object is copied. In the Java language, this process is called "refrigeration" and "thawing". Here we will test this method:
[size=+0][size=+0]php Code

* [size=+0][size=+0] $TV 1 = new Television ();
* $TV 2 = unserialize (serialize ($TV 1));//serialization and deserialization
*

* $contr 1 = $tv 1->getcontrol ();//Get TV1 remote control CONTR1
* $contr 2 = $tv 2->getcontrol ();//Get TV2 remote control CONTR2
*

* Echo
$TV 1; The object ID of//TV1 is #1
* Echo
'
';
* Echo
$contr 1;//contr1 's object ID is # #
* Echo
'
';
* Echo
$TV 2; The object ID of//TV2 is #4
* Echo
'
';
* Echo
$contr 2;//contr2 's Object ID is # #


we can see the output, TV1 and TV2 have different remotes. This is much more convenient than scenario 1, serialization is a recursive process, we do not need to ignore how many objects are referenced within the object and how many layers of objects are referenced, we can completely copy. Note When using this scenario, we cannot trigger the __clone magic method to complete some additional operations, and of course we can do a clone operation after the deep copy to trigger the __clone magic method, but will have little effect on efficiency. In addition, this scenario triggers the __sleep and __wakeup magic methods of the copied object and all referenced objects, so these situations need to be considered.



Summary
different methods of object replication have different effects, and we should consider which approach to use and how to improve replication based on specific application requirements. PHP5 's object-oriented features are closer to Java, and we believe we can draw on a lot of valuable experience from Java.
Clone
  • Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.