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 tooUse 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; // 10Um 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 2022Alterar $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 hpEditar 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 hpAgora 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
clonesempre 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
clonefaz 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.