Menu
Coddy logo textTech

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 método mágico __clone anteriormente neste curso. Agora vamos explorar a diferença crítica entre a clonagem rasa e a profunda quando objetos contêm outros objetos como propriedades.

Por padrão, o PHP realiza uma cópia superficial (shallow copy) ao clonar. Valores escalares são duplicados, mas as propriedades de objeto permanecem como referências para os 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 - London

Observe 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 onde objetos aninhados também são 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:

Paris

Agora cada Person tem seu próprio Address independente. Quando seus objetos contêm múltiplos objetos aninhados, você deve clonar cada um em __clone para alcançar a verdadeira independência entre o original e a cópia.

challenge icon

Desafio

Fácil

Vamos construir um sistema de gerenciamento de documentos que demonstra a diferença entre clonagem rasa (shallow) e profunda (deep). Você criará documentos que contêm informações do autor e garantirá que a clonagem de um documento crie uma cópia verdadeiramente independente.

Você organizará seu código em três arquivos:

  • Author.php — Crie uma classe Author que representa o autor de um documento. Use a promoção de construtor para definir um $name (string) público e um $email (string) público.
  • Document.php — Crie uma classe Document que contém um autor. Inclua o arquivo Author. A classe deve:
    • Usar a promoção de construtor para um $title (string) público e um $author (Author) público
    • Implementar o método mágico __clone() para realizar a clonagem profunda — quando um documento for clonado, seu autor também deve ser clonado para que as alterações no autor do clone não afetem o original
    • Ter um método getInfo() que retorna "[title] by [author name] ([author email])"
  • main.php — Inclua o arquivo Document. Você receberá três entradas: um título de documento, um nome de autor e um e-mail de autor.

    Crie um Document com um Author usando as entradas fornecidas. Clone o documento, depois modifique o nome do autor do clone anexando " (Copy)" a ele e altere o título do clone prefixando "Copy of " a ele.

    Imprima duas linhas:

    • As informações do documento original
    • As informações do documento clonado

    Se a sua clonagem profunda for implementada corretamente, o autor do documento original deve permanecer inalterado mesmo após a modificação do autor do clone.

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.

Folha de consulta

Por padrão, o PHP realiza uma cópia rasa (shallow copy) ao clonar objetos. Valores escalares são duplicados, mas propriedades de objeto permanecem como referências aos mesmos objetos.

Exemplo de clonagem rasa:

<?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 - London

Alterar $clone->name não afeta o original, mas alterar o objeto address aninhado afeta, porque ambos os objetos compartilham a mesma instância de Address.

Para criar uma cópia profunda (deep copy) onde objetos aninhados também são clonados, implemente o método mágico __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: Paris

Quando objetos contêm múltiplos objetos aninhados, você deve clonar cada um no __clone para alcançar a verdadeira independência entre o original e a cópia.

Experimente você mesmo

<?php

require_once 'Document.php';

// Ler entradas
$title = trim(fgets(STDIN));
$authorName = trim(fgets(STDIN));
$authorEmail = trim(fgets(STDIN));

// TODO: Criar um Autor com o nome e e-mail fornecidos

// TODO: Criar um Documento com o título fornecido e o Autor

// TODO: Clonar o documento

// TODO: Modificar o nome do autor do clone anexando " (Copy)" a ele

// TODO: Modificar o título do clone prefixando "Copy of " a ele

// TODO: Imprimir as informações do documento original

// TODO: Imprimir as informações do documento clonado

?>
quiz iconTeste seus conhecimentos

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