__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.99De forma predeterminada, PHP realiza una copia superficial: copia directamente todos los valores de las propiedades. Esto funciona bien para los valores escalares, pero los objetos dentro de tu objeto siguen haciendo referencia a la misma instancia. El método mágico __clone() te 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: 0El método __clone() se llama en el nuevo objeto después de realizar la copia superficial. Aquí es donde restableces los ID, creas copias nuevas de los objetos anidados o realizas cualquier limpieza necesaria para que el clon sea verdaderamente independiente.
Desafío
FácilConstruyamos un sistema de versionado de documentos que demuestre cómo la clonación crea copias independientes y cómo el método mágico __clone() permite personalizar lo que ocurre cuando se clona un objeto.
Organizarás tu código en dos archivos:
Document.php: Crea una claseDocumentque represente un documento versionado. Usa la promoción de constructor para definir un$titlepúblico (string), un$contentpúblico (string) y un$versionpúblico (integer, con un valor predeterminado de 1). Añade una propiedad privada$createdAtque almacene la marca de tiempo actual (usadate('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$createdAtdebe 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 unDocumentcon el título y el contenido. Después 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() permite controlar lo que ocurre durante la clonación. El documento original conserva su versión y su hora de creación, mientras que el clon se convierte automáticamente en una nueva versión con una marca de tiempo actualizada, perfecto para realizar un seguimiento del historial de documentos en el que cada clon representa una nueva revisión.
Pruébalo tú mismo
<?php
require_once 'Document.php';
// Leer entradas
$title = trim(fgets(STDIN));
$content = trim(fgets(STDIN));
$newContent = trim(fgets(STDIN));
// TODO: Crea un Document con el título y el contenido
// TODO: Clona el documento para crear una nueva versión
// TODO: Actualiza el contenido del clon a la nueva cadena de contenido
// TODO: Imprime 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
?>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
1Fundamentos de la POO
Archivos externosIntroducción a la POOClases frente a objetosLa palabra clave $thisMétodosPropiedadesConstructor (__construct)Destructor (__destruct)Repaso: calculadora simple4Herencia
Herencia básicaLa palabra clave parent::Sobrescritura de métodosLa palabra clave finalClases abstractasRepaso - Jerarquía de empleados7Encapsulación
Público, protegido, privadoModificadores de acceso en profundidadGetters y settersOcultación de la informaciónPromoción del constructor (8.0)Repaso: sistema de registros de estudiantes10Conceptos avanzados de OOP
Composición vs. herenciaInyección de dependenciasClases anónimasEnums (PHP 8.1)Fibras (PHP 8.1)Análisis profundo de la clonación de objetosGeneradores e iteradores13Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository2Namespaces y carga automática
Introducción a los NamespacesLa palabra clave useEstándar de carga automática PSR-4Autoloader de ComposerRepaso: proyecto organizado5Interfaces y contratos
Introducción a las interfacesImplementación de interfacesImplementación de múltiples interfacesInterfaces vs. clase abstractaTipado con interfacesRepaso - Calculadora de formas8Métodos mágicos
Introducción a los métodos mágicos__toString y __debugInfo__get, __set, __isset, __unset__call y __callStatic__clone y clonación de objetos__serialize y __unserializeRepaso: colección personalizada3Propiedades de clase
Propiedades de instancia vs. estáticasConstantes en clasesMétodos y propiedades estáticosPropiedades privadas y protegidasPropiedades de solo lectura (PHP 8.1)Repaso: gestor de cuentas bancarias6Polimorfismo
Repaso de la sobrescritura de métodosPolimorfismo mediante interfacesAnotaciones de tipo y tipos uniónEnlace estático tardíoRepaso: procesador de pagos9Traits
Introducción a los TraitsUso de múltiples TraitsResolución de conflictos entre TraitsMétodos abstractos en TraitsTraits frente a la herencia12Patrones de diseño, parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón StrategyPractica por tu cuenta: Compilador de PHP online