Análise Profunda da 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 método mágico __clone anteriormente neste curso. Agora, vamos explorar a diferença crucial entre clonagem superficial e profunda 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 documentos que demonstra a diferença entre clonagem superficial e profunda. Você criará documentos que contêm informações sobre o autor e garantirá que clonar um documento crie uma cópia verdadeiramente independente.
Você organizará seu código em três arquivos:
Author.php: crie uma classeAuthorque represente o autor de um documento. Use a promoção de propriedades no construtor para definir um$namepúblico (string) e um$emailpúblico (string).Document.php: crie uma classeDocumentque contenha um autor. Inclua o arquivo Author. A classe deve:- Usar a promoção de propriedades no construtor para um
$titlepúblico (string) e um$authorpúblico (Author) - Implementar o método mágico
__clone()para realizar uma clonagem profunda; quando um documento for clonado, seu autor também deverá ser clonado para que as alterações no autor da cópia não afetem o original - Ter um método
getInfo()que retorne"[title] by [author name] ([author email])"
- Usar a promoção de propriedades no construtor para um
main.php: inclua o arquivo Document. Você receberá três entradas: o título de um documento, o nome de um autor e o e-mail de um autor.Crie um
Documentcom umAuthorusando as entradas fornecidas. Clone o documento; em seguida, modifique o nome do autor da cópia acrescentando" (Copy)"a ele e altere o título da cópia acrescentando"Copy of "no início.Imprima duas linhas:
- As informações do documento original
- As informações do documento clonado
Se a clonagem profunda tiver sido implementada corretamente, o autor do documento original deverá permanecer inalterado mesmo após a modificação do autor da cópia.
Este desafio demonstra por que a clonagem profunda é importante: sem a implementação adequada de __clone(), ambos os documentos 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 OOP
Arquivos externosIntrodução à OOPClasses vs. objetosA palavra-chave $thisMétodosPropriedadesConstrutor (__construct)Destrutor (__destruct)Recapitulação - Calculadora simples4Herança
Herança BásicaA Palavra-chave parent::Sobrescrita de MétodosA Palavra-chave finalClasses AbstratasRecapitulação - Hierarquia de Funcionários7Encapsulamento
Público, Protegido, PrivadoModificadores de Acesso em ProfundidadeGetters e SettersOcultação de InformaçõesPromoção de Construtor (8.0)Recapitulação - Sistema de Registros de Alunos10Conceitos Avançados de OOP
Composição vs. HerançaInjeção de DependênciaClasses AnônimasEnums (PHP 8.1)Fibras (PHP 8.1)Análise Profunda da 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 às InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesInterface vs Classe AbstrataTipagem 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 NulosTipos de União e InterseçãoClasses de ExceçãoHierarquia de Exceções PersonalizadaTry, Catch, FinallyRecapitulação - Validador de Formulário14Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses de Livros e Usuários3Propriedades de Classes
Propriedades de Instância vs. EstáticasConstantes em ClassesMétodos e Propriedades EstáticosPropriedades Privadas e ProtegidasPropriedades Somente para Leitura (PHP 8.1)Recapitulação - Gerenciador de Contas Bancárias6Polimorfismo
Revisão da Sobrescrita de MétodosPolimorfismo via InterfacesIndicação de Tipos e Tipos UnionVinculação Estática TardiaRecapitulação - Processador de Pagamentos9Traits
Introdução a TraitsUsando Múltiplos TraitsResolução de Conflitos entre 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