W3docs

clone

Aprende cómo la palabra clave clone de PHP copia objetos, qué es una copia superficial y cómo usar __clone() para realizar copias profundas.

La palabra clave clone de PHP

En PHP, los objetos se manejan por referencia. Cuando asignas una variable de object a otra con =, ambas variables apuntan al mismo object — si cambias una, la otra también cambia. La palabra clave clone rompe ese vínculo: crea un object completamente nuevo que comienza como duplicado del existente, de modo que puedes modificar la copia sin alterar el original.

Esta página cubre la sintaxis de clone, la diferencia entre una copia superficial y una copia profunda (la principal fuente de errores con clone), y el método mágico __clone() que te permite controlar qué ocurre durante la clonación.

Si eres nuevo en objetos, lee primero Clases y objetos de PHP y Constructores.

Sintaxis

$copy = clone $original;

clone devuelve un nuevo object. El original no se modifica, y $copy es una instancia independiente cuyas propiedades se copian de $original.

Asignación vs. clone

Esta es la razón por la que existe clone. Con una asignación simple, ambas variables hacen referencia al mismo object:

<?php
class Counter
{
    public int $value = 0;
}

$a = new Counter();
$b = $a;          // same object, NOT a copy
$b->value = 10;

echo $a->value . PHP_EOL; // 10 — $a changed too

Usa clone para obtener un object genuinamente independiente:

<?php
class Counter
{
    public int $value = 0;
}

$a = new Counter();
$b = clone $a;    // independent copy
$b->value = 10;

echo $a->value . PHP_EOL; // 0 — original is untouched
echo $b->value . PHP_EOL; // 10

Un ejemplo básico

<?php
class Car
{
    public string $make;
    public string $model;
    public int $year;

    public function __construct(string $make, string $model, int $year)
    {
        $this->make = $make;
        $this->model = $model;
        $this->year = $year;
    }
}

$original = new Car("Ford", "Mustang", 2022);
$copy = clone $original;

$copy->make = "Chevrolet";
$copy->model = "Corvette";

echo "Original: {$original->make} {$original->model} {$original->year}" . PHP_EOL;
echo "Copy:     {$copy->make} {$copy->model} {$copy->year}" . PHP_EOL;

// Output:
// Original: Ford Mustang 2022
// Copy:     Chevrolet Corvette 2022

Cambiar $copy no afecta a $original, porque son dos objetos separados.

Copia superficial: el principal inconveniente

Por defecto, clone realiza una copia superficial. Las propiedades escalares (strings, enteros, booleanos) se copian por valor, pero si una propiedad contiene otro object, solo se copia la referencia — tanto el original como el clon terminan apuntando al mismo object anidado.

<?php
class Engine
{
    public function __construct(public int $horsepower) {}
}

class Car
{
    public function __construct(public Engine $engine) {}
}

$original = new Car(new Engine(300));
$copy = clone $original;

// Both cars still share ONE Engine object
$copy->engine->horsepower = 500;

echo "Original engine: {$original->engine->horsepower} hp" . PHP_EOL;
echo "Copy engine:     {$copy->engine->horsepower} hp" . PHP_EOL;

// Output:
// Original engine: 500 hp
// Copy engine:     500 hp

Editar el motor del clon también modificó el motor del original — casi nunca es lo que se desea.

Copia profunda con __clone()

El método mágico __clone() se ejecuta automáticamente en el nuevo object justo después de ser duplicado. Úsalo para clonar cualquier object anidado, de modo que la copia tenga los suyos propios e independientes (una copia profunda):

<?php
class Engine
{
    public function __construct(public int $horsepower) {}
}

class Car
{
    public function __construct(public Engine $engine) {}

    public function __clone()
    {
        // Give the clone its own Engine instead of sharing the original's
        $this->engine = clone $this->engine;
    }
}

$original = new Car(new Engine(300));
$copy = clone $original;

$copy->engine->horsepower = 500;

echo "Original engine: {$original->engine->horsepower} hp" . PHP_EOL;
echo "Copy engine:     {$copy->engine->horsepower} hp" . PHP_EOL;

// Output:
// Original engine: 300 hp
// Copy engine:     500 hp

Ahora los dos coches tienen motores separados, por lo que cambiar uno no afecta al otro. __clone() es el lugar adecuado para cualquier ajuste posterior a la copia: restablecer un ID generado automáticamente, borrar un valor en caché, o realizar copias profundas de objetos anidados y arrays de objetos.

Cuándo usar clone

  • Copias de trabajo / borradores — duplica un object para que el usuario pueda editar una copia mientras el original se conserva (piensa en "Guardar como").
  • Patrón prototipo — preconfigurar un object y usar clone cada vez que necesites una nueva instancia preconfigurada, en lugar de ejecutar un constructor costoso cada vez.
  • Ayudantes de inmutabilidad — devolver un clon modificado en lugar de mutar $this, una técnica común en objetos de valor y DTOs.

Recurre a clone cuando necesites específicamente un segundo object independiente; si solo necesitas leer el mismo object desde dos lugares, una referencia simple es suficiente.

Aspectos importantes

  • clone realiza una copia superficial por defecto — los objetos anidados se comparten, no se duplican.
  • Define __clone() para realizar una copia profunda o cualquier otro ajuste por copia.
  • __clone() se ejecuta en el nuevo object, donde $this es el clon.
  • clone es para objetos. Los arrays en PHP ya se copian por valor en la asignación, por lo que no necesitan clone.

Práctica

Práctica
¿Qué hace el método __clone() en PHP?
¿Qué hace el método __clone() en PHP?
Was this page helpful?