Mergulho Profundo em Clonagem de Objetos
Parte da seção Programação Orientada a Objetos do Journey de PHP da Coddy. Lição 61 de 91.
Você aprendeu sobre o __clone method mágico anteriormente neste curso. Agora vamos explorar a diferença crítica entre a clonagem superficial e deep quando os objetos contêm outros objetos como propriedades.
Por padrão, PHP realiza uma cópia superficial ao clonar. Os valores escalares são duplicados, mas as propriedades dos objetos permanecem como referências aos mesmos 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;
Saída:
Alice - LondonObserve que alterar $clone->name não afetou o original, mas alterar a cidade do endereço afetou! Ambos os objetos compartilham a mesma instância de Address.
Para criar uma cópia profunda em que os objetos aninhados também sejam clonados, implemente __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;
Saída:
ParisAgora cada Person tem seu próprio Address independente. Quando seus objetos contêm vários objetos aninhados, você deve clonar cada um em __clone para alcançar uma verdadeira independência entre o original e a cópia.
Desafio
FácilVamos criar um sistema de gerenciamento de document que demonstra a diferença entre clonagem superficial e clonagem profunda. Você criará document que contêm informações de author e garantirá que clonar um document crie uma cópia realmente independente.
Você organizará seu código em três arquivos:
Author.php: Crie uma classeAuthorque represente o author de um document. Use constructor promotion para definir um$namepúblico (string) e um$emailpúblico (string).Document.php: Crie uma classeDocumentque contenha um author. Inclua o arquivo Author. A classe deve:- Usar constructor promotion para um
$titlepúblico (string) e um$authorpúblico (Author) - Implementar o método mágico
__clone()para realizar cloning profundo; quando um document é clonado, seu author também deve ser clonado, para que as alterações no author do clone não afetem o original - Ter um method
getInfo()que returns"[title] by [author name] ([author email])"
- Usar constructor promotion para um
main.php: Inclua o arquivo Document. Você receberá três entradas: um título de document, um nome de author e um email de author.Crie um
Documentcom umAuthorusando os inputs provided. Clone o document e, em seguida, modifique o nome do author do clone appending" (Copy)"a ele e altere o título do clone prepending"Copy of "a ele.Print duas linhas:
- As informações do document original
- As informações do document clonado
Se o seu cloning profundo estiver implementado corretamente, o author do document original should permanecer inalterado mesmo após modificar o author do clone.
Este desafio demonstra por que o cloning profundo é importante: sem a implementação adequada de __clone(), ambos os document compartilhariam o mesmo objeto Author, e alterar um afetaria o outro.
Experimente você mesmo
<?php
require_once 'Document.php';
// Ler entradas
$title = trim(fgets(STDIN));
$authorName = trim(fgets(STDIN));
$authorEmail = trim(fgets(STDIN));
// TODO: Crie um Author com o nome e o email fornecidos
// TODO: Crie um Document com o título fornecido e o Author
// TODO: Clone o documento
// TODO: Modifique o nome do autor do clone acrescentando " (Copy)" a ele
// TODO: Modifique o título do clone prefixando "Copy of " a ele
// TODO: Imprima as informações do documento original
// TODO: Imprima as informações do documento clonado
?>Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos ExternosIntrodução à POOClasses vs ObjetosA Palavra-chave $thisMétodosPropriedadesConstrutor (__construct)Destrutor (__destruct)Recapitulação - Calculadora Simples4Herança
Herança BásicaA Palavra-chave parent::Sobrescrita de MétodoA Palavra-chave finalClasses AbstratasRecapitulação - Hierarquia de Funcionários7Encapsulamento
Público, Protegido, PrivadoModificadores de Acesso em DetalhesGetters e SettersOcultação de InformaçãoPromoção de Construtor (8.0)Recapitulação - Sistema de Registro de Alunos10Conceitos Avançados de POO
Composição vs HerançaInjeção de DependênciaClasses AnônimasEnums (PHP 8.1)Fibers (PHP 8.1)Mergulho Profundo em Clonagem de ObjetosGeradores e Iteradores13Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Repository2Namespaces e Autoloading
Introdução a NamespacesA Palavra-chave usePadrão de Autoloading PSR-4Autoloader do ComposerRecapitulação - Projeto Organizado5Interfaces e Contratos
Introdução a InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesInterface vs Classe AbstrataType Hinting com InterfacesRecapitulação - Calculadora de Formas8Métodos Mágicos
Introdução aos Métodos Mágicos__toString e __debugInfo__get, __set, __isset, __unset__call e __callStatic__clone e Clonagem de Objetos__serialize e __unserializeRecapitulação - Coleção Personalizada11Sistema de Tipos e Tratamento de Erros
Declarações de TiposTipos AnuláveisTipos de União e InterseçãoClasses de ExceçãoHierarquia de Exceções PersonalizadasTry, Catch, FinallyRecapitulação - Validador de Formulário14Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses Livro e Usuário3Propriedades de Classe
Propriedades de Instância vs EstáticasConstantes em ClassesMétodos e Propriedades EstáticosPropriedades Privadas e ProtegidasPropriedades Readonly (PHP 8.1)Recapitulação - Gerenciador de Conta Bancária6Polimorfismo
Sobrescrita de Métodos RevisitadaPolimorfismo via InterfacesType Hinting e Union TypesLate Static BindingRecapitulação - Processador de Pagamentos9Traits
Introdução a TraitsUsando Múltiplos TraitsResolução de Conflitos de TraitsMétodos Abstratos em TraitsTraits vs Herança12Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão StrategyPratique por conta própria: Compilador de PHP online