W3docs

clone

Scopri come la parola chiave PHP clone copia gli oggetti, perché produce una copia superficiale e come usare il metodo magico __clone() per le copie profonde.

La parola chiave PHP clone

In PHP, gli oggetti sono gestiti per riferimento. Quando assegni una variabile oggetto a un'altra con =, entrambe le variabili puntano allo stesso oggetto: modificandone una, cambia anche l'altra. La parola chiave clone rompe questo legame: crea un nuovo oggetto che inizia come duplicato di uno esistente, così puoi modificare la copia senza toccare l'originale.

Questa pagina tratta la sintassi di clone, la differenza tra una copia superficiale e una profonda (la principale causa di bug con clone), e il metodo magico __clone() che ti permette di controllare cosa accade durante la clonazione.

Se sei nuovo agli oggetti, leggi prima PHP Classes and Objects e Constructors.

Sintassi

$copy = clone $original;

clone restituisce un nuovo oggetto. L'originale rimane invariato e $copy è un'istanza indipendente le cui proprietà sono copiate da $original.

Assegnazione vs. clone

Questo è il motivo per cui esiste clone. Con una semplice assegnazione, entrambe le variabili fanno riferimento allo stesso oggetto:

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

Usa clone per ottenere un oggetto veramente separato:

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

Un esempio di base

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

Modificare $copy lascia intatto $original, perché sono due oggetti separati.

Copia superficiale: l'insidia principale

Per impostazione predefinita, clone produce una copia superficiale. Le proprietà scalari (string, int, boolean) vengono copiate per valore, ma se una proprietà contiene un altro object, viene copiato solo il riferimento — sia l'originale che il clone finiscono per puntare allo stesso object annidato.

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

Modificare il motore del clone ha cambiato anche il motore dell'originale — quasi mai quello che si desidera.

Copia profonda con __clone()

Il metodo magico __clone() viene eseguito automaticamente sul nuovo oggetto subito dopo la duplicazione. Usalo per clonare gli oggetti annidati, in modo che la copia abbia i propri indipendenti (una copia profonda):

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

Ora le due auto hanno motori separati, quindi modificarne uno non influisce sull'altro. __clone() è il posto giusto per qualsiasi correzione per copia: reimpostare un ID generato automaticamente, svuotare un valore nella cache, o copiare in profondità oggetti annidati e array di oggetti.

Quando usare clone

  • Copie di lavoro / bozze — duplica un object in modo che un utente possa modificare una copia mentre l'originale viene conservato (come "Salva come").
  • Pattern Prototype — preconfiguare un object e usare clone ogni volta che serve una nuova istanza preimpostata, invece di eseguire un costoso costruttore ogni volta.
  • Helper di immutabilità — restituire un clone modificato invece di mutare $this, una tecnica comune nei value object e nei DTO.

Usa clone quando hai specificamente bisogno di un secondo object indipendente; se devi solo leggere lo stesso object da due posti, un semplice riferimento è sufficiente.

Punti da ricordare

  • clone produce una copia superficiale per impostazione predefinita — gli object annidati sono condivisi, non duplicati.
  • Definisci __clone() per eseguire una copia profonda o qualsiasi altra correzione per copia.
  • __clone() viene eseguito sul nuovo object, dove $this è il clone.
  • Clone è per gli object. Gli array in PHP vengono già copiati per valore all'assegnazione, quindi non hanno bisogno di clone.

Esercizi

Pratica
Cosa fa il metodo __clone() in PHP?
Cosa fa il metodo __clone() in PHP?
Was this page helpful?