Cuando estamos trabajando con variables y objetos podemos llegar a pensar que para copiar un objeto basta con asignarlo a otra variable así:

<?php 
class Persona { 
    private $_nombre; 
    public function __construct( $nombre ){ 
        $this->_nombre = $nombre; 
    } 
    public function __toString(){ 
        return $this->_nombre; 
    } 
} 
$persona = new Persona( 'Juan' ); 
$persona2 = $persona; 
?>

Pero esto no es correcto, debido a que los objetos trabajan por referencias, esto quiere decir que aunque tengamos ahora dos variables diferentes como son $persona y $persona2, si cambiamos un valor en una de ellas se reflejara en ambas porque estamos trabajando sobre el mismo objeto:

<?php 
class Persona { 
    private $_nombre; 
    public function __construct( $nombre ){ 
        $this->_nombre = $nombre; 
    } 

    public function __toString(){ 
        return $this->_nombre; 
    } 

    public function setNombre( $nombre ){ 
        $this->_nombre = $nombre; 
    } 
} 

$persona = new Persona( 'Juan' ); 
$persona2 = $persona; 
$persona2->setNombre( 'Pepe '); //Cambio el nombre sobre $persona2 
var_dump($persona); //Imprime: object(Persona)#1 (1) { ["_nombre":"Persona":private]=> string(5) "Pepe " } 
var_dump($persona2); //Imprime: object(Persona)#1 (1) { ["_nombre":"Persona":private]=> string(5) "Pepe " } 
?>

Como ves, aunque solo hemos modificado una de las variables se ha producido el cambio en ambas, si nos fijamos atentamente podemos ver que var_dump nos imprime el tipo de objeto y la instancia “object(Persona)#1” en este caso es 1 para ambas variables.

Para poder clonar un objeto correctamente debemos de usar le instrucción clone en la asignación de la variable:

<?php 
//Clonamos el objeto 
$persona3 = clone $persona; 
var_dump($persona3); //Imprime: object(Persona)#2 (1) { ["_nombre":"Persona":private]=> string(5) "Pepe " } 
?>

Atentos al numero de la instancia que en este caso ya no es uno sino 2 (object(Persona)#2), hemos clonado el objeto correctamente por lo tanto al realizar un cambio en $persona o en $persona2 no debería de afectar para nada a $persona3, vemos un ejemplo:

<?php 
class Persona { 
    private $_nombre; 
        public function __construct( $nombre ){ 
            $this->_nombre = $nombre; 
        } 
        public function __toString(){ 
            return $this->_nombre; 
        } 
        public function setNombre( $nombre ){ 
            $this->_nombre = $nombre; 
        } 
    } 
    $persona = new Persona( 'Juan' ); 
    $persona2 = $persona; 
    $persona3 = clone $persona; 

    //Realizamos un cambio en $persona 
    $persona->setNombre( 'Manolo' ); 

    //Las variables $persona y $persona2 se verán afectadas por el cambio 
    var_dump($persona); //Imprime: object(Persona)#1 (1) { ["_nombre":"Persona":private]=> string(6) "Manolo" } 
    var_dump($persona2); //Imprime: object(Persona)#1 (1) { ["_nombre":"Persona":private]=> string(6) "Manolo" } 

    //La variable $persona3 no se verá afectada 
    var_dump($persona3); //Imprime: object(Persona)#2 (1) { ["_nombre":"Persona":private]=> string(4) "Juan" } 
    ?>

Pero puede darse el caso de que necesitemos provocar algún cambio en el objeto al clonarlo, por ejemplo asignarle un nombre especial, limpiar algunas variables que contentan parámetros que ya no necesitemos, etcétera. Para este caso es que existe el método mágico __clone.

El método mágico __clone se dispara en el momento de clonar el objeto mediante la instrucción clone, y al igual que muchos de los métodos mágicos que ya hemos visto nos da la posibilidad de ejecutar sentencias o generar cambios al dispararse, por ejemplo vamos a cambiar el atributo nombre del objeto al clonarlo:

<?php 
class Persona { 
    private $_nombre; 
    public function __construct( $nombre ){ 
        $this->_nombre = $nombre; 
    } 

    public function __toString(){ 
        return $this->_nombre; 
    } 

    public function setNombre( $nombre ){ 
        $this->_nombre = $nombre; 
    } 

    public function __clone(){ 
        $this->_nombre = 'Objeto Clonado'; 
    } 
} 
$persona = new Persona( 'Juan' ); 
$persona2 = clone $persona; 

var_dump($persona); //Imprime: object(Persona)#1 (1) { ["_nombre":"Persona":private]=> string(4) "Juan" } 
var_dump($persona2); //Imprime: object(Persona)#2 (1) { ["_nombre":"Persona":private]=> string(14) "Objeto Clonado" } 
?>

No es necesario pasarlo ningún parámetro a __clone, y como se aprecia en el ejemplo su uso es muy sencillo, simplemente definimos la rutina a ejecutar y al clonar el objeto nos ha cambiado el nombre de ‘Juan‘ a ‘Objeto clonado‘.

En el próximo artículo hablare sobre la carga dinámica de clases y con esto terminaré el tema de los métodos mágicos para poder seguir adelante con la herencia de clases y otros temas.