Clonación de objetos
PHP Manual
PHP Manual»Clases y objetos»Clonación de objetos

La creación de una copia de un objeto con exactamente las mismas propiedades no siempre es el comportamiento deseado. Un buen ejemplo para ilustrar la necesidad de un constructor de copia: si se tiene un objeto que representa una ventana GTK y el objeto contiene el recurso que representa esa ventana GTK, al crear una copia, se puede desear crear una nueva ventana con las mismas propiedades, pero que el nuevo objeto contenga un recurso que represente la nueva ventana. Otro ejemplo: si el objeto contiene una referencia a otro objeto que utiliza, al replicar el objeto padre se puede desear crear una nueva instancia de ese otro objeto, de modo que la réplica tenga su propia copia independiente.

Una copia de objeto se crea utilizando la palabra clave clone (que invoca al método __clone() del objeto, si ha sido definido).

$copy_of_object = clone $object;

Cuando un objeto es clonado, PHP realiza una copia superficial de todas las propiedades del objeto. Todas las propiedades que son referencias a otras variables permanecerán como referencias.

function __clone(): void

Una vez realizada la clonación, si se ha definido un método __clone(), el método __clone() del nuevo objeto será llamado, para permitir que cada propiedad que deba ser modificada lo sea.

Ejemplo #1 Ejemplo de duplicación de objetos

<?php
class SubObject
{
  static $instances = 0;
  public $instance;

  public function __construct() {
    $this->instance = ++self::$instances;
  }

  public function __clone() {
    $this->instance = ++self::$instances;
  }
}

class MyCloneable
{
  public $object1;
  public $object2;

  function __clone()
  {
    // Fuerza la copia de this->object, de lo contrario
    // apuntará al mismo objeto.
    $this->object1 = clone $this->object1;
  }
}

$obj = new MyCloneable();

$obj->object1 = new SubObject();
$obj->object2 = new SubObject();

$obj2 = clone $obj;

print "Objeto original:\n";
print_r($obj);

print "Objeto clonado:\n";
print_r($obj2);

?>

El ejemplo anterior mostrará:

Objeto original:
MyCloneable Object
(
    [object1] => SubObject Object
        (
            [instance] => 1
        )

    [object2] => SubObject Object
        (
            [instance] => 2
        )

)
Objeto clonado:
MyCloneable Object
(
    [object1] => SubObject Object
        (
            [instance] => 3
        )

    [object2] => SubObject Object
        (
            [instance] => 2
        )

)

Es posible acceder a un miembro de un objeto recién clonado en una sola expresión:

Ejemplo #2 Acceso a un miembro de un objeto recién clonado

<?php
$dateTime = new DateTime();
echo (clone $dateTime)->format('Y');
?>

Resultado del ejemplo anterior es similar a:

2016

Clonación con sustitución de propiedades

A partir de PHP 8.5.0, clone también está disponible como función, cuyo segundo parámetro withProperties acepta un array que asocia nombres de propiedades con los valores que recibe la copia. Solo se sustituyen las propiedades indicadas; las demás conservan el valor con el que fueron copiadas.

Las sustituciones se aplican después de la ejecución de __clone() y respetan la visibilidad de todas las propiedades. Las propiedades readonly pueden modificarse en la copia aunque ya estuvieran inicializadas en el objeto original, lo que hace que la función resulte adecuada para los métodos que devuelven una copia modificada.

Ejemplo #3 Clonación de un objeto con sustitución de propiedades

<?php
class Point {
    public function __construct(
        public readonly int $x,
        public readonly int $y,
    ) {}

    public function withX(int $x): static
    {
        return clone($this, ['x' => $x]);
    }
}

$p = new Point(1, 2);
$q = $p->withX(10);

echo $q->x, ' ', $q->y;
?>

El ejemplo anterior mostrará:

10 2
To Top