[Reading Notes-PHP] PHP deep copy and shallow copy

Source: Internet
Author: User
Tags getcolor

Statement: This article is reprinted.

Address: http://www.2cto.com/kf/201110/109659.html

In this article, we will discuss the object replication technology of PhP5 in a simple and in-depth manner. In this article, please respect copyright errors or improper content and hope to be pointed out.

Origin of object Replication

Why does an object have the concept of "copying", which is closely related to the object Value passing method in PhP5. Let's take a look at the following simple code:

/* TV */class television {/* screen height */protected $ _ screenlength = 300; /*** screen width */protected $ _ screenhight = 200;/*** TV appearance color */protected $ _ color = 'black '; /*** return TV appearance color */Public Function getcolor () {return $ this-> _ color ;} /*** set the TV appearance color */Public Function setcolor ($ color) {$ this-> _ color = (string) $ color; return $ this ;}} $ TV1 = new television (); $ TV2 = $ TV1;

This Code defines the television class of a TV set. $ TV1 is an instance of a TV set. Then, we assign the value of $ TV1 to $ T2. Now we have two TVs $ TV1 and $ TV2. Is that true? Let's test it.

 

Echo 'color of TV1 is :'. $ TV1-> getcolor (); // The TV1 color is black echo '<br>'; echo 'color of TV2 is :'. $ TV2-> getcolor (); // The TV2 color is black echo '<br>'; // color TV2 to white $ TV2-> setcolor ('white '); echo 'color of TV2 is :'. $ TV2-> getcolor (); // The color of TV2 is white echo '<br>'; echo 'color of TV1 is :'. $ TV1-> getcolor (); // The TV1 color is white.

First, we can see that the colors of TV1 and TV2 are both black. Now we want to change the color of TV2, so we set the color to white. Then we can see that the color of TV2 has indeed become white, it seems that we have met our requirements, but it is not as smooth as we think. When we look at the color of TV1, we find that TV1 is also converted from black to white. We have not reset the TV1 color. Why does TV1 change from black to white? This is because in PhP5, the object's value assignment and passing are both "referenced. PhP5 uses the Zend engine II, and objects are stored in independent structured objects.
Store, instead of storing other common variables in zval (Objects in PhP4 are stored in zval like General variables ). In zval, only the object pointer is stored, 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 data. Only keep the same object pointer and the other zval notifies the object store to which the specified object points. Because the object is located in the object store, any changes we make to it will affect all the zval structures that hold the object pointer-any changes to the target object in the program will affect the source object .. This makes PHP objects look like they are always passed through reference. Therefore, the above TV2 and TV1 actually point to the same TV instance. The operations we do on TV1 or TV2 are actually for this same instance. Therefore, our "copy" failed. It seems that the direct variable assignment method cannot copy objects. Therefore, PhP5 provides an operation dedicated to copying objects, that is
Clone. This is the origin of object replication.

Use clone to copy objects

We now use the clone language structure of PhP5 to copy objects. The Code is as follows:

$ TV1 = new television (); $ TV2 = clone $ TV1; echo 'color of TV1 is :'. $ TV1-> getcolor (); // The TV1 color is black echo '<br>'; echo 'color of TV2 is :'. $ TV2-> getcolor (); // The TV2 color is black echo '<br>'; // change TV2 to white $ TV2-> setcolor ('white '); echo 'color of TV2 is :'. $ TV2-> getcolor (); // The color of TV2 is white echo '<br>'; echo 'color of TV1 is :'. $ TV1-> getcolor (); // The TV1 color is black.

For the first line of this code, we use the clone keyword to copy TV1. Now we have a copy of TV1 TV2. We still use the previous method to check whether the copy is successful. We can see that we have changed the TV2 color to white, and the TV1 color to black, so that our copy operation is successful.

_ Clone magic Method

Now we have considered this situation. Every TV set should have its own number, which should be unique like our ID card number. So when we copy a TV set, we do not want this number to be copied to avoid some trouble. One of the strategies we come up with is to clear the numbers of the assigned TVs, and then re-allocate the numbers as needed.

The _ clone magic method is specifically used to solve this problem, __the clone magic method will be triggered when the object is copied (that is, the clone operation. We modified the code of television for TV sets and added the numbering attribute and the _ clone method. The Code is as follows.

 

/***** TV class */class television {/***** TV Number */protected $ _ identity = 0; /* ** screen height */protected $ _ screenlength = 300;/* screen width */protected $ _ screenhight = 200; /*** TV appearance color */protected $ _ color = 'black';/*** return 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 );}}

Next we will copy such a TV set object.

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

We have produced a TV set TV1 and set its number to 111111. Then we copied TV1 to TV2 using clone. At this time, the _ clone magic method is triggered, this method works directly with the Copied object TV2. In the _ clone method, we call the setidentity member method to clear the _ identity attribute of TV2, so that we can re-numbers it later. From this we can see that the _ clone magic method allows us to easily perform some additional operations when cloning objects.

Fatal Defects of clone operations

Can clone achieve the desired replication effect? In some cases, you may find that the clone operation is not as perfect as we think. Modify the above TV set and then perform a test.

Each TV is equipped with a remote control, so we will have a remote control class. The remote control and the TV are in an "aggregation" relationship (relative to "Combination" relationship, is a weak dependency, because in general, even if the TV can be used normally without remote control), now our TV objects should all hold a reference to the remote control object. Next let's look at the code

/***** TV class */class television {/***** TV Number */protected $ _ identity = 0; /* ** screen height */protected $ _ screenlength = 300;/* screen width */protected $ _ screenhight = 200; /*** TV appearance color */protected $ _ color = 'black';/*** remote control object */protected $ _ control = NULL; /*** Add the remote control object */public function _ construct () {$ this-> setcontrol (New telecontrol ());} /*** set the remote control object */Public Function setcontrol (telecontrol $ Control) {$ this-> _ control = $ control; return $ this ;} /*** return the remote control object */Public Function getcontrol () {return $ this-> _ control;}/*** return the 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 a TV set object below and observe the remote control object of the TV set.

 

$ TV1 = new television (); $ TV2 = clone $ TV1; $ contr1 = $ TV1-> getcontrol (); // obtain the TV1 Remote Control contr1 $ contr2 = $ TV2-> getcontrol (); // obtain the TV2 Remote Control contr2 echo $ TV1; // The Object ID of TV1 is #1 echo '<br>'; echo $ contr1; // the Object ID of contr1 is #2 Echo '<br>'; echo $ TV2; // The Object ID of TV2 is #3 Echo '<br>'; echo $ contr2; // the Object ID of contr2 is #2

After copying, we can view the Object ID and copy TV2 from TV1 through the clone operation. The object IDs of TV1 and TV2 are 1 and 3, respectively, this indicates that TV1 and TV2 reference two different TV sets, which meets the clone operation result. Then we obtained the remote control objects contr1 and contr2 of TV1 respectively. By viewing their object IDs, we found that the object IDs of contr1 and contr2 are both 2, this indicates that they are referenced to the same object. That is to say, although we copied TV2 from TV1, the remote control is not copied. Each TV set should be equipped with a remote control, here TV2 and TV1 share a remote control, which is obviously unreasonable.

It can be seen that the clone operation has such a huge defect: When the clone operation is used to copy an object, when the Copied object references other objects, the referenced object will not be copied. However, this situation is very common. Nowadays, "synthesis/aggregation multiplexing" is often promoted to replace "inheritance reuse ", "merging" and "aggregation" means to allow an object to reference another object and reuse the method of the referenced object. We should consider this situation when using clone. So how should we solve such a defect when cloning objects? You may soon think of the _ clone magic method mentioned earlier, which is indeed a solution.

Solution 1: Use _ clone magic to compensate

We have already introduced the _ clone magic method usage. In the _ clone method, we can rereference the references of other objects in the Copied object to a new object. Next let's take a look at the modified _ clone () magic method:

 

Public Function _ clone () {$ this-> setidentity (0); // reset a remote control object $ this-> setcontrol (New telecontrol ());}

In row 04th, we re-set a remote control for the copied TV Object. We can view the Object ID according to the previous method and find that the remote control of the two TVs has different object IDs, in this way, our problem is solved.

However, this method is probably not very good. If there are multiple references to other objects in the Copied object, we must reset them one by one in the _ clone method, even worse, if the class of the Copied object is provided by a third party and we cannot modify the code, the copy operation will basically fail.

We use clone to copy objects. This replication is called "shortest copy": all variables of the Copied object contain the same value as the original object, all references to other objects still point to the original object. That is to say, the shortest copy only copies the objects to be considered, rather than the objects referenced by it. Compared with "Shallow copy", there is also a "Deep copy": all the variables of the Copied object contain the same value as the original object, except variables that reference other objects. That is to say, deep replication copies all the objects referenced by the objects to be copied. Deep replication requires deciding on how many layers to penetrate into. This is an uncertain problem. In addition, circular references may occur, which must be handled with caution. Our solution 2 will be a deep replication solution.

Solution 2: Use serialization for deep Replication

PHP has serialize and unserialize functions. We only need to use serialize () to write an object to a stream and then read it back from the stream, then the object is copied. In Java, this process is called "Refrigerating" and "unfreezing ". Next we will test this method:

 

$ TV1 = new television (); $ TV2 = unserialize (serialize ($ TV1); // serialize and deserialize $ contr1 = $ TV1-> getcontrol (); // obtain the TV1 Remote Control contr1 $ contr2 = $ TV2-> getcontrol (); // obtain the TV2 Remote Control contr2 echo $ TV1; // The Object ID of TV1 is #1 echo '<br>'; echo $ contr1; // the Object ID of contr1 is #2 Echo '<br>'; echo $ TV2; // The Object ID of TV2 is #4 echo '<br>'; echo $ contr2; // the Object ID of contr2 is #5

The output result shows that TV1 and TV2 have different remote controls. This is much more convenient than solution 1. serialization is a recursive process. We don't need to care how many objects are referenced inside the object and how many layers of objects are referenced, we can completely copy the data. Note that when using this scheme, we cannot trigger the _ clone magic method to complete some additional operations. Of course, we can perform another clone operation after deep replication to trigger the _ clone magic method, it only has a slight impact on efficiency. In addition, this scheme will trigger the _ sleep and _ wakeup magic methods of the Copied object and all referenced objects, so these situations need to be considered.

Summary

Different object replication methods have different effects. We should consider which method to use and how to improve the replication method based on specific application requirements. The object-oriented features of PhP5 are similar to those of Java. I believe we can learn a lot from Java.

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.