What is the purpose of the magical __clone method?

Asked

Viewed 1,771 times

12

In PHP we have the magic method __clone. It serves to define a behavior when you clone an object through the keyword clone.

So far so good. But I did not understand very well why to have this magical method, since the word clone if only one object has been cloned.

Example 1:

 $a = new ArrayObject(['nome' => 'Wallace']);

 $b = clone $a;

Another detail I wanted to understand is that I’ve seen some libraries in PHP use this magic method for operations similar to the one below:

Example 2:

  class X {
       public function __construct (Y $y) {
          $this->y = $y;
       }

       public function __clone() {
          $this->y = clone $this->y;
       }
  }

Based on the above observations, I ask:

  • Is there any case where it is really necessary to define a behavior for cloning an object?

  • Why do some libraries use __clone to clone a property corresponding to an instance of an object (as in example 2)?

  • 4

    But he really is a magician?

  • 1

    Yes, he’s Magical, Magical

  • 4

    http://i.stack.Imgur.com/Ykzbv.jpg

  • 2

    It also serves to deprive your class of being cloned. When you make the method 'private'. It is widely used in standard Singleton Pattern design.

  • @Ivanferrer good observation, that’s good.

  • 1

    http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=205960&type=card

  • This is a method I’ve never understood what it’s really for

Show 2 more comments

3 answers

17


Deep clone

Because cloning, in general, involves copying the entire content of the object in a profound way (deep). That is, it also copies the referenced objects within that object. Eventually one may want until every object tree is cloned, if possible (the referenced objects need to be able to be cloned deeply).

Since the way to copy these objects can vary greatly, you have to write the code that will do this. This happens a lot when you secure external resources in the class, such as files and GUI objects, but is not limited to these things. Anything that needs full data independence needs deep cloning.

Shallow clone

If you do not create this method PHP will clone shallowly (Shallow), that is, it will copy only the object, its members by reference will have only the references copied that will point to the same object that its original object pointed. This may be what you want in some cases, but not at all.

Then a lot of people get lost creating classes. Most programmers don’t understand all the implications of creating a class. It usually works because in general the classes do nothing sophisticated, or even they were not even necessary at all. Actually just doesn’t give a lot of trouble because PHP codes are what I always say, just scripts simple. If they were complex applications in fact many classes would start to explode. In general its use is very contained and deep cloning is not usually necessary. Where they are needed are usually written by programmers who have more notion of how computing works as a whole.

Clone != Copy

Note that cloning, even shallow, is different from copying the object, the pure copy only copies the object reference, not the object.

Examples

In the example of the question $b will have an object just like $a, but it will be another object. They will be completely independent, each with its own life, changing one does not change the other. You cloned and did not simply copy. Whether cloning will be shallow or deep depends on the type of the variable object $a. As far as I know ArrayObject does not clone deeply, at least has nothing to say this in documentation.

In class X is doing this with your member, ensuring that a copy of the member is made and not only the reference.

$x = new X(new Y());
$y = clone $x;

Then you know that $x and $y shall be independent. But the most important thing is that the y, accessed by $this will also be independent in each of the objects, ie this member will be copied as well. If not had this cloning. Both $x.y, how much $y.y would point to the same object, and changing into one, would change into the other, they would not be independent. Probably not what you wanted.

class A {
    public $b;
 
    public function __construct(B $b) {
        $this->b = $b;
    }
}
 
class B {}
 
class C extends A {
    public function __clone() {
        $this->b = clone $this->b;
    }
}
 
$a = new A(new B);
$aa = clone $a;
$b = $a;
$c = new C(new B);
$cc = clone $c;
echo "CÓPIA\n";
var_dump($a === $b); //é igual, ambos apontam para o mesmo objeto
var_dump($a->b === $b->b); //continua igual, é o mesmo objeto, não pode ser diferente
echo "SEM __CLONE\n";
var_dump($a === $aa); //é diferente, copiou o objeto
var_dump($a->b === $aa->b); //é igual, o membro continua sendo o mesmo objeto apontado
echo "COM __CLONE\n";
var_dump($c === $cc); //é diferente, copiou o objeto
var_dump($c->b === $cc->b); //é diferente, copiou o objeto referenciado pelo membro

Behold working in the ideone. And in the repl it.. Also put on the Github for future reference.

The magical method __clone() is always called by the command clone language, when the method is available to that object, if it is not available, the cloning will be shallow.

Documentation.

7

Summary

Basically the magic method __clone() serves as a "callback" after a cloning.

When an object is cloned the compiler searches for the magic method __clone() and, if it exists, is invoked.

Independent bodies and allocation by reference

A cloned object is independent of the original from which it was cloned.

However, you may want to copy or make assignments by reference of the members of the original object. For this there is the magic method __clone() where you can make these copies.

The reason why there is no deep and complete copy of an entire object is that you don’t always need a deep copy of the entire object. At least not within the main use purpose we make of PHP.

In the PHP manual there are good enough examples to understand: http://php.net/manual/en/language.oop5.cloning.php

On the two issues at the end

Is there any case where it is really necessary to define a behaviour for cloning an object?

Why some libraries use __clone to clone a property corresponding to an instance of an object (as in example 2)?

It is difficult to answer because the reason/reason/circumstance depends on a context.

Without understanding the context becomes impossible to answer.

-5

After cloning is completed, if a __clone() method is defined, the newly created object will have its __clone() method called, allowing any property to be changed.

http://php.net/manual/en/language.oop5.cloning.php

Nothing more, Nothing Less.

// Force a copy of this->object, otherwise
// it will point to same object.
$this->object1 = clone $this->object1;
  • I did not understand the rest of the answer after the part taken from the Manual.

  • 4

    I thought this was SO-PT...

  • 4

    I’m sorry to be so blunt, but that +2 was badly voted on. Really, the answer does not explain anything, just makes a reference to the manual (which in turn never explains anything right).

  • 2

    The answer is simplistic and answers the question asked in the title of the question, but ignores the content of the question, where the PA already demonstrates knowing that the routine is called and seeks to know a case of practical use of it. Compared to the others it is incomplete, but it was given before, so I don’t think it deserves so many negatives.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.