W3docs

clone

Aprenda como a palavra-chave clone do PHP copia objetos, por que faz uma cópia rasa e como usar o método mágico __clone() para controlar cópias profundas.

A Palavra-chave clone do PHP

No PHP, os objetos são manipulados por referência. Quando você atribui uma variável de object a outra com =, ambas as variáveis apontam para o mesmo object — altere uma e a outra também muda. A palavra-chave clone quebra esse vínculo: ela cria um object completamente novo que começa como uma duplicata de um existente, para que você possa modificar a cópia sem tocar no original.

Esta página aborda a sintaxe do clone, a diferença entre uma cópia rasa e uma cópia profunda (a maior fonte de bugs com clone), e o método mágico __clone() que permite controlar o que acontece durante a clonagem.

Se você é novo em objetos, leia Classes e Objetos PHP e Construtores primeiro.

Sintaxe

$copy = clone $original;

clone retorna um novo object. O original permanece intocado, e $copy é uma instância independente cujas propriedades são copiadas de $original.

Atribuição vs. clone

Esta é a razão pela qual clone existe. Com uma atribuição simples, ambas as variáveis fazem referência ao mesmo object:

<?php
class Counter
{
    public int $value = 0;
}

$a = new Counter();
$b = $a;          // same object, NOT a copy
$b->value = 10;

echo $a->value . PHP_EOL; // 10 — $a changed too

Use clone para obter um object genuinamente separado:

<?php
class Counter
{
    public int $value = 0;
}

$a = new Counter();
$b = clone $a;    // independent copy
$b->value = 10;

echo $a->value . PHP_EOL; // 0 — original is untouched
echo $b->value . PHP_EOL; // 10

Um exemplo básico

<?php
class Car
{
    public string $make;
    public string $model;
    public int $year;

    public function __construct(string $make, string $model, int $year)
    {
        $this->make = $make;
        $this->model = $model;
        $this->year = $year;
    }
}

$original = new Car("Ford", "Mustang", 2022);
$copy = clone $original;

$copy->make = "Chevrolet";
$copy->model = "Corvette";

echo "Original: {$original->make} {$original->model} {$original->year}" . PHP_EOL;
echo "Copy:     {$copy->make} {$copy->model} {$copy->year}" . PHP_EOL;

// Output:
// Original: Ford Mustang 2022
// Copy:     Chevrolet Corvette 2022

Alterar $copy não afeta $original, porque são dois objetos separados.

Cópia rasa: o principal problema

Por padrão, clone faz uma cópia rasa. Propriedades escalares (strings, ints, booleans) são copiadas por valor, mas se uma propriedade contém outro object, apenas a referência é copiada — tanto o original quanto o clone acabam apontando para o mesmo object aninhado.

<?php
class Engine
{
    public function __construct(public int $horsepower) {}
}

class Car
{
    public function __construct(public Engine $engine) {}
}

$original = new Car(new Engine(300));
$copy = clone $original;

// Both cars still share ONE Engine object
$copy->engine->horsepower = 500;

echo "Original engine: {$original->engine->horsepower} hp" . PHP_EOL;
echo "Copy engine:     {$copy->engine->horsepower} hp" . PHP_EOL;

// Output:
// Original engine: 500 hp
// Copy engine:     500 hp

Editar o motor do clone também alterou o motor do original — quase nunca é isso que você quer.

Cópia profunda com __clone()

O método mágico __clone() é executado automaticamente no novo object logo após ser duplicado. Use-o para clonar quaisquer objetos aninhados para que a cópia tenha os seus próprios independentes (uma cópia profunda):

<?php
class Engine
{
    public function __construct(public int $horsepower) {}
}

class Car
{
    public function __construct(public Engine $engine) {}

    public function __clone()
    {
        // Give the clone its own Engine instead of sharing the original's
        $this->engine = clone $this->engine;
    }
}

$original = new Car(new Engine(300));
$copy = clone $original;

$copy->engine->horsepower = 500;

echo "Original engine: {$original->engine->horsepower} hp" . PHP_EOL;
echo "Copy engine:     {$copy->engine->horsepower} hp" . PHP_EOL;

// Output:
// Original engine: 300 hp
// Copy engine:     500 hp

Agora os dois carros têm motores separados, então alterar um não afeta o outro. __clone() é o lugar certo para qualquer ajuste por cópia: redefinir um ID gerado automaticamente, limpar um valor em cache, ou fazer cópia profunda de objetos aninhados e arrays de objetos.

Quando usar clone

  • Cópias de trabalho / rascunhos — duplique um object para que um usuário possa editar uma cópia enquanto o original é preservado (pense em "Salvar Como").
  • Padrão Prototype — pré-configure um object e use clone sempre que precisar de uma nova instância pré-configurada, em vez de executar um construtor custoso a cada vez.
  • Auxiliares de imutabilidade — retorne um clone modificado em vez de mutar $this, uma técnica comum em value objects e DTOs.

Use clone quando precisar especificamente de um segundo object independente; se você só precisa ler o mesmo object de dois lugares, uma referência simples é suficiente.

Pontos importantes

  • clone faz uma cópia rasa por padrão — objetos aninhados são compartilhados, não duplicados.
  • Defina __clone() para realizar uma cópia profunda ou qualquer outro ajuste por cópia.
  • __clone() é executado no novo object, onde $this é o clone.
  • Clone é para objetos. Arrays no PHP já são copiados por valor na atribuição, portanto não precisam de clone.

Prática

Prática
O que o método __clone() faz no PHP?
O que o método __clone() faz no PHP?
Was this page helpful?