Menu
Coddy logo textTech

__clone y clonación de objetos

Parte de la sección Programación Orientada a Objetos del Journey de PHP de Coddy — lección 48 de 91.

Cuando asignas un objeto a otra variable en PHP, no creas una copia; ambas variables apuntan al mismo objeto. Para crear una copia independiente real, necesitas usar la palabra clave clone:

<?php
class Product {
    public function __construct(
        public string $name,
        public float $price
    ) {}
}

$original = new Product("Laptop", 999.99);
$copy = clone $original;

$copy->price = 899.99;
echo $original->price . " - " . $copy->price;

Salida:

999.99 - 899.99

Por defecto, PHP realiza una copia superficial: copia todos los valores de las propiedades directamente. Esto funciona bien para valores escalares, pero los objetos dentro de su objeto siguen haciendo referencia a la misma instancia. El método mágico __clone() le permite personalizar este comportamiento:

<?php
class Order {
    public function __construct(
        public int $id,
        public array $items = []
    ) {}
    
    public function __clone(): void {
        $this->id = 0;
        $this->items = [];
    }
}

$order1 = new Order(101, ["Book", "Pen"]);
$order2 = clone $order1;

echo "Original: " . $order1->id . ", Clone: " . $order2->id;

Salida:

Original: 101, Clone: 0

El método __clone() se llama en el nuevo objeto después de que se realiza la copia superficial. Aquí es donde se restablecen los IDs, se crean copias nuevas de los objetos anidados o se realiza cualquier limpieza necesaria para que el clon sea verdaderamente independiente.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de versiones de documentos que demuestre cómo la clonación crea copias independientes y cómo el método mágico __clone() te permite personalizar lo que sucede cuando se clona un objeto.

Organizarás tu código en dos archivos:

  • Document.php — Crea una clase Document que represente un documento con versiones. Usa la promoción de constructor para definir un $title público (string), un $content público (string) y un $version público (integer, con valor por defecto 1). Añade una propiedad privada $createdAt que almacene la marca de tiempo actual (usa date('Y-m-d H:i:s') en el constructor). Tu documento necesita:
    • getCreatedAt() — devuelve la marca de tiempo de creación
    • __clone() — cuando se clona un documento, la versión debe incrementarse en 1, y el $createdAt debe restablecerse a la marca de tiempo actual (el clon es una nueva versión creada "ahora")
  • main.php — Incluye el archivo Document. Recibirás tres entradas: un título, un contenido y una nueva cadena de contenido para la versión clonada. Crea un Document con el título y el contenido. Luego clónalo para crear una nueva versión y actualiza el contenido del clon con la nueva cadena de contenido. Imprime cuatro líneas:
    • La versión del documento original
    • La versión del documento clonado
    • El contenido del documento original
    • El contenido del documento clonado

Este sistema muestra cómo __clone() te permite controlar lo que sucede durante la clonación. El documento original mantiene su versión y hora de creación, mientras que el clon se convierte automáticamente en una nueva versión con una marca de tiempo fresca, ideal para el seguimiento del historial de documentos donde cada clon representa una nueva revisión.

Hoja de referencia

Para crear una copia independiente de un objeto, utiliza la palabra clave clone:

<?php
class Product {
    public function __construct(
        public string $name,
        public float $price
    ) {}
}

$original = new Product("Laptop", 999.99);
$copy = clone $original;

$copy->price = 899.99;
echo $original->price . " - " . $copy->price;
// Salida: 999.99 - 899.99

Por defecto, PHP realiza una copia superficial (shallow copy) de todos los valores de las propiedades. Para personalizar el comportamiento de la clonación, utiliza el método mágico __clone():

<?php
class Order {
    public function __construct(
        public int $id,
        public array $items = []
    ) {}
    
    public function __clone(): void {
        $this->id = 0;
        $this->items = [];
    }
}

$order1 = new Order(101, ["Book", "Pen"]);
$order2 = clone $order1;

echo "Original: " . $order1->id . ", Clone: " . $order2->id;
// Salida: Original: 101, Clone: 0

El método __clone() se llama en el nuevo objeto después de que se realiza la copia superficial, lo que permite restablecer propiedades o crear copias independientes de objetos anidados.

Pruébalo tú mismo

<?php

require_once 'Document.php';

// Leer entradas
$title = trim(fgets(STDIN));
$content = trim(fgets(STDIN));
$newContent = trim(fgets(STDIN));

// TODO: Crear un Document con el título y el contenido

// TODO: Clonar el documento para crear una nueva versión

// TODO: Actualizar el contenido del clon con la nueva cadena de contenido

// TODO: Imprimir cuatro líneas:
// 1. La versión del documento original
// 2. La versión del documento clonado
// 3. El contenido del documento original
// 4. El contenido del documento clonado

?>
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos