W3docs

clone

Apprenez comment le mot-clé PHP clone copie les objets, pourquoi il fait une copie superficielle et comment utiliser la méthode magique __clone() pour contrôler les copies profondes.

Le mot-clé PHP clone

En PHP, les objets sont gérés par référence. Lorsque vous assignez une variable d'object à une autre avec =, les deux variables pointent vers le même object — modifiez l'un et l'autre change aussi. Le mot-clé clone rompt ce lien : il crée un tout nouvel object qui commence comme un duplicata d'un object existant, vous permettant ainsi de modifier la copie sans toucher à l'original.

Cette page couvre la syntaxe de clone, la différence entre une copie superficielle et une copie profonde (la principale source de bugs liés à clone), ainsi que la méthode magique __clone() qui vous permet de contrôler ce qui se passe pendant le clonage.

Si vous débutez avec les objets, lisez d'abord Classes et objets PHP et Constructeurs.

Syntaxe

$copy = clone $original;

clone retourne un nouvel object. L'original reste intact, et $copy est une instance indépendante dont les propriétés sont copiées depuis $original.

Assignation vs. clone

C'est la raison d'être de clone. Avec une simple assignation, les deux variables font référence au même 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

Utilisez clone pour obtenir un object véritablement séparé :

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

Modifier $copy laisse $original intact, car ce sont deux objets séparés.

Copie superficielle : le principal piège

Par défaut, clone effectue une copie superficielle. Les propriétés scalaires (strings, ints, booleans) sont copiées par valeur, mais si une propriété contient un autre object, seule la référence est copiée — l'original et le clone finissent par pointer vers le même object imbriqué.

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

Modifier le moteur du clone a aussi modifié le moteur de l'original — ce qui n'est presque jamais ce que vous souhaitez.

Copie profonde avec __clone()

La méthode magique __clone() s'exécute automatiquement sur le nouvel object juste après sa duplication. Utilisez-la pour cloner tous les objets imbriqués afin que la copie dispose de ses propres instances indépendantes (une copie profonde) :

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

Les deux voitures ont maintenant des moteurs séparés, donc modifier l'un n'affecte pas l'autre. __clone() est l'endroit approprié pour toute correction par copie : réinitialiser un ID auto-généré, vider une valeur mise en cache, ou effectuer une copie profonde des objets imbriqués et des arrays d'objets.

Quand utiliser clone

  • Copies de travail / brouillons — dupliquer un object pour qu'un utilisateur puisse modifier une copie pendant que l'original est préservé (pensez à « Enregistrer sous »).
  • Patron prototype — pré-configurer un object et le cloner chaque fois que vous avez besoin d'une nouvelle instance pré-paramétrée, plutôt que d'exécuter un constructeur coûteux à chaque fois.
  • Helpers d'immuabilité — retourner un clone modifié plutôt que de muter $this, technique courante dans les value objects et les DTO.

Faites appel à clone lorsque vous avez spécifiquement besoin d'un second object indépendant ; si vous devez seulement lire le même object depuis deux endroits, une simple référence suffit.

À retenir

  • clone effectue une copie superficielle par défaut — les objets imbriqués sont partagés, pas dupliqués.
  • Définissez __clone() pour effectuer une copie profonde ou tout autre ajustement par copie.
  • __clone() s'exécute sur le nouvel object, où $this est le clone.
  • clone est destiné aux objets. Les arrays en PHP sont déjà copiés par valeur lors de l'assignation, ils n'ont donc pas besoin de clone.

Pratique

Pratique
Que fait la méthode __clone() en PHP ?
Que fait la méthode __clone() en PHP ?
Was this page helpful?