Análisis profundo de la clonación de objetos
Parte de la sección Programación Orientada a Objetos del Journey de PHP de Coddy. Lección 61 de 91.
Aprendiste sobre el método mágico __clone anteriormente en este curso. Ahora exploremos la diferencia fundamental entre la clonación superficial y la profunda cuando los objetos contienen otros objetos como propiedades.
De forma predeterminada, PHP realiza una copia superficial al clonar. Los valores escalares se duplican, pero las propiedades de los objetos permanecen como referencias a los mismos objetos:
<?php
class Address {
public function __construct(public string $city) {}
}
class Person {
public function __construct(
public string $name,
public Address $address
) {}
}
$original = new Person("Alice", new Address("Paris"));
$clone = clone $original;
$clone->name = "Bob";
$clone->address->city = "London";
echo $original->name . " - " . $original->address->city;
Salida:
Alice - LondonObserva que cambiar $clone->name no afectó al original, ¡pero cambiar la ciudad de la dirección sí! Ambos objetos comparten la misma instancia de Address.
Para crear una copia profunda en la que los objetos anidados también se clonen, implementa __clone:
<?php
class Person {
public function __construct(
public string $name,
public Address $address
) {}
public function __clone(): void {
$this->address = clone $this->address;
}
}
$original = new Person("Alice", new Address("Paris"));
$clone = clone $original;
$clone->address->city = "London";
echo $original->address->city;
Salida:
ParisAhora cada Person tiene su propio Address independiente. Cuando tus objetos contienen varios objetos anidados, debes clonar cada uno en __clone para lograr una verdadera independencia entre el objeto original y la copia.
Desafío
FácilConstruyamos un sistema de gestión de documentos que demuestre la diferencia entre la clonación superficial y la clonación profunda. Crearás documentos que contengan información del autor y te asegurarás de que clonar un documento cree una copia verdaderamente independiente.
Organizarás tu código en tres archivos:
Author.php: Crea una claseAuthorque represente al autor de un documento. Usa la promoción del constructor para definir un$namepúblico (string) y un$emailpúblico (string).Document.php: Crea una claseDocumentque contenga un autor. Incluye el archivo de Author. La clase debe:- Usar la promoción del constructor para un
$titlepúblico (string) y un$authorpúblico (Author) - Implementar el método mágico
__clone()para realizar una clonación profunda; cuando se clone un documento, su autor también debe clonarse, de modo que los cambios realizados en el autor de la copia no afecten al original - Tener un método
getInfo()que devuelva"[title] by [author name] ([author email])"
- Usar la promoción del constructor para un
main.php: Incluye el archivo de Document. Recibirás tres entradas: el título de un documento, el nombre de un autor y el correo electrónico de un autor.Crea un
Documentcon unAuthorusando las entradas proporcionadas. Clona el documento, después modifica el nombre del autor de la copia añadiéndole" (Copy)"y cambia el título de la copia anteponiéndole"Copy of ".Imprime dos líneas:
- La información del documento original
- La información del documento clonado
Si la clonación profunda está implementada correctamente, el autor del documento original debe permanecer sin cambios incluso después de modificar el autor de la copia.
Este desafío demuestra por qué es importante la clonación profunda: sin una implementación adecuada de __clone(), ambos documentos compartirían el mismo objeto Author y cambiar uno afectaría al otro.
Pruébalo tú mismo
<?php
require_once 'Document.php';
// Leer entradas
$title = trim(fgets(STDIN));
$authorName = trim(fgets(STDIN));
$authorEmail = trim(fgets(STDIN));
// TODO: Crear un Author con el nombre y el email proporcionados
// TODO: Crear un Document con el título proporcionado y el Author
// TODO: Clonar el documento
// TODO: Modificar el nombre del autor del clon añadiendo " (Copy)" a él
// TODO: Modificar el título del clon anteponiendo "Copy of " a él
// TODO: Imprimir la info del documento original
// TODO: Imprimir la info 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