Copying objects

In PHP, objects are always handled as references. This means that when you pass an object into a function, any changes you make to it in there are reflected outside the function. For example, consider this piece of code:

public function namechange($dog) {
    $dog->Name = 'Dozer';
}

namechange($poppy);
print $poppy->Name . "\n";

Here we define a function that accepts one variable, $dog, then changes its name to Dozer. We then pass our $poppy dog into the function, and output its name - unsurprisingly, it outputs "Dozer" rather than "Poppy". Sometimes it is important to only work on copies of objects - you might not want to affect the state of the original. To do this, we use the built-in keyword "clone", which performs a complete copy of the object. For example, we could use the namechange() function above like this:

namechange(clone $poppy);

That would create a copy of $poppy and pass it into namechange(), leaving the original $poppy untouched. Here is the output of the code now:

Creating Poppy
Creating a poodle
My name is Poppy. If you find me, please call 555-1234
Dozer is no more...
Poppy
Poppy is no more...

Note that Dozer is still mentioned - that is because the copied object passed into namechange() gets its name changed to Dozer, then, when the function ends, the copied object is automatically destroyed by PHP, and its destructor is called. However, $poppy lives on untouched, as you can see from the last two lines.

Internally, the clone keyword copies all the variables from the first object to a new object, then calls a magic function __clone() for the class it is copying. You can override __clone() if you want, thereby giving you the flexibility to perform extra actions when a variable is copied - you can think of it as a constructor for copied object. Have a look at this piece of code:

public function __clone() {
    $this->Name .= '++';
}

That function will be called on the copied object, and will set the copied object to have the same name as the original, with ++ tacked onto the end. So, rather than the clone being called Poppy, it will be called Poppy++. If we clone the clone, it will be called Poppy++++, and so on.

For really advanced functionality, you can also call parent::__clone() to work your way up the inheritance chain and call the __clone() function of the parent class. Again, all the copying of data is already done, so all the __clone() function would be required to do is make any last-minute tweaks to the copy. Here's how that looks:

<?php
    abstract class dog {
        public function __clone() {
            echo "In dog clone\n";
        }
    }

    class poodle extends dog {
        public $Name;

        public function __clone() {
            echo "In poodle clone\n";
            parent::__clone();
        }
    }

    $poppy = new poodle();
    $poppy->Name = "Poppy";

    $rover = clone $poppy;
?>

 

Want to learn PHP 7?

Hacking with PHP has been fully updated for PHP 7, and is now available as a downloadable PDF. Get over 1200 pages of hands-on PHP learning today!

If this was helpful, please take a moment to tell others about Hacking with PHP by tweeting about it!

Next chapter: Comparing objects with == and === >>

Previous chapter: Deleting objects

Jump to:

 

Home: Table of Contents

Copyright ©2015 Paul Hudson. Follow me: @twostraws.