Hudzilla.org - the homepage of Paul Hudson
Contents > Objects Wish List | Report Bug | About Me ]

6.11     Copying objects

This is NOT the latest copy of this book; click here for the latest version.

From PHP 5 onwards, 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;
?>

Author's Note: Early releases of PHP 5 made you call the __clone() function directly, and provided a $this and $that variable to allow you to do custom copying. Sadly this ended up being documented in several top PHP books that were rushed out to capitalise on PHP 5, and now the code no longer works - don't call __clone() directly to copy an object!





<< 6.10.3 Deleting objects   6.12 Comparing objects with == and === >>
Table of Contents
Want to see this stuff in print? PHP in a Nutshell takes the core topics covered here, adds in thousands of edits from the editorial team and myself, and combines them to make an unbeatable reference for PHP programmers at all levels.



My latest book has hundreds more tips on how to use PHP, Apache, and MySQL, plus Perl, Python, shell scripts, performance tuning, and more!



Top-right shadow
 
Bottom-left shadow Bottom shadow

Comments from other readers
Gus Jones - 06 Sep 2008

The preceeding chapters have been outstanding. I think there are better tutorials on PHP OOP - but that does not detract from my opinion that this site taken as a whole is a wonderful document on PHP...this OOP chapter needs a going over...

TxtEdMacs - 06 Sep 2008

Last example had problems too with the __clone() function, using the lines as given:

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

resulted in this warning: "Warning: Missing argument 1 for poodle::__construct() in /home/txtedmacs/PHP-reference/PHP-text-Paul-Hudson/test_class_clone_2.php on line 32"

Nonetheless, all the output in the lines following matched those I saw when I compress the two lines above into:

$poppy = new poodle("Poppy");

The lines seen were:

Creating a poodle
Creating Poppy
In poodle clone
In dog clone
Poppy is no more...
Poppy is no more...

I am somewhat surprised either worked, since the definition of abstract is a class that cannot create an instance from it. An abstract class can only be used to create a new class by subclassing. I thought that meant the code in an abstract class would not execute, yet in the poodle class definition the __clone() is directed back to the parent to actually execute. What am I missing? [I am told that an abstract class in C# is more of an outline with no code in the functions, hence, by its very structure does not execute.]

TxtEdMacs - 06 Sep 2008

"A PHP User" - Thanks! Whoever you are.

I was having severe doubts on whether it was even worth my time continuing to read this chapter. I tried a number of changes within the classes to attempt to make this work without success. Reading the php documentation and starting another book also made me skeptical of the syntax, since most of what I found mentions using the __clone {} function within the class definitions.

I like this book's examples and testable code, I hate the tendency seen more recently to be imprecise as to the intended placement of code fragments.

A PHP User - 06 Sep 2008

I tried inserting the namechange function from the examples above under both my dog class and my poodle class, but got the following error message when namechange($poppy) was encountered:

Fatal error: Call to undefined function namechange()

However, all worked well if the function was not in any class and had the public declaration removed!



Add comment
Please note that by posting a comment here you are committing it to the public domain. This is important so that others can make use of your code themselves, and also so that I can incorporate helpful notes directly into the main text. Comments are limited to 2000 characters in length.

If you are reporting an error in the content, please tell me directly.

Your name/email address:
Your comment:
 
Now, in order to verify that you're a real person, please answer this simple question: what is nine plus seven?
The answer is:
(please write in
numbers, eg 19)


Top-right shadow
 
Bottom-left shadow Bottom shadow