OUJOOD.COM
Le mot-clé clone en PHP : principe et syntaxe
PHP 4 ne permettait pas de dupliquer un objet de façon contrôlée. PHP 5 a introduit le mot-clé clone et la méthode magique __clone() pour combler ce manque. Ces deux outils restent inchangés en PHP 7 et PHP 8.
Quand vous écrivez $copie = clone $original, PHP crée une nouvelle instance avec les mêmes valeurs de propriétés. Point important : __clone() ne peut pas être appelée directement — PHP l'invoque automatiquement après la copie, si elle est définie dans la classe.
La différence avec new : new crée un objet vide et appelle __construct(), clone repart d'un objet existant et ses propriétés sont déjà remplies.
<?php
// Cloner un objet : $copie_objet est une nouvelle instance indépendante
$copie_objet = clone $objet_original;
?>Copie superficielle et copie profonde
Sans __clone(), PHP fait une copie superficielle (shallow copy) : les propriétés scalaires (string, int, float…) sont dupliquées, mais les propriétés qui contiennent des objets restent des références vers les mêmes instances. Modifier un sous-objet depuis le clone modifie aussi l'original.
Pour obtenir une copie profonde (deep copy), il faut implémenter __clone() et y cloner explicitement chaque propriété objet qui doit être indépendante.
Exemple 1 : clonage simple avec propriétés scalaires
Avec des propriétés de type string ou int, la copie superficielle suffit : les deux objets sont déjà totalement indépendants sans __clone().
<?php
class Personne {
private $nom;
private $prenom;
function __construct($nom, $prenom) {
$this->setNom($nom);
$this->setPrenom($prenom);
}
function setNom($nom) {
$this->nom = $nom;
}
function setPrenom($prenom) {
$this->prenom = $prenom;
}
function getNomPrenom() {
return($this->nom." ".$this->prenom);
}
}
$personne = new Personne("DUBOIS", "Pierre");
// Clone : copie superficielle suffisante ici, les propriétés sont des strings
$clonePersonne = clone $personne;
// Modifier le clone n'affecte pas l'original
$clonePersonne->setPrenom("Caen");
print_r($personne); // prenom => Pierre (inchangé)
print_r($clonePersonne); // prenom => Caen
?>Résultat :
Personne Object
(
[nom:Personne:private] => DUBOIS
[prenom:Personne:private] => Pierre
)
Personne Object
(
[nom:Personne:private] => DUBOIS
[prenom:Personne:private] => Caen
)
Les deux objets ont divergé après setPrenom("Caen"). C'est le comportement attendu : pour des types scalaires, clone suffit sans __clone().
Exemple 2 : copie profonde avec __clone() et objets imbriqués
Quand une propriété contient un objet, la copie superficielle laisse les deux instances pointer vers le même sous-objet. L'exemple suivant montre comment __clone() permet de contrôler ce comportement propriété par propriété.
<?php
header("Content-type: text/plain");
// Compteur statique pour numéroter chaque instance créée ou clonée
class SubObject
{
static $instances = 0;
public $instance;
public function __construct() {
$this->instance = ++self::$instances;
}
// __clone() est appelée automatiquement : le clone reçoit un nouveau numéro
public function __clone() {
$this->instance = ++self::$instances;
}
}
class MyCloneable
{
public $object1;
public $object2;
function __clone()
{
// Copie profonde : object1 est cloné, nouvelle instance indépendante
$this->object1 = clone $this->object1;
// object2 n'est pas cloné : il reste partagé entre l'original et le clone
}
}
$obj = new MyCloneable();
$obj->object1 = new SubObject(); // instance = 1
$obj->object2 = new SubObject(); // instance = 2
$obj2 = clone $obj;
// __clone() de MyCloneable est appelée : object1 est reclôné (instance = 3)
print("Objet original :\n");
print_r($obj);
print("Objet cloné :\n");
print_r($obj2);
?>Résultat :
Objet original :
MyCloneable Object
(
[object1] => SubObject Object
(
[instance] => 1
)
[object2] => SubObject Object
(
[instance] => 2
)
)
Objet cloné :
MyCloneable Object
(
[object1] => SubObject Object
(
[instance] => 3
)
[object2] => SubObject Object
(
[instance] => 2
)
)
object1 du clone a reçu l'instance 3 — c'est un nouvel objet indépendant. object2 affiche toujours 2 dans les deux cas : il s'agit de la même référence, partagée. Ce comportement est parfois voulu (objet de configuration partagé, par exemple), parfois non — __clone() vous laisse décider propriété par propriété.
Exemple 3 : clonage avec un tableau de valeurs scalaires
Les tableaux PHP de types primitifs (strings, entiers, flottants) se comportent comme des scalaires lors du clonage : ils sont copiés automatiquement, sans __clone(). Un tableau d'objets, lui, nécessiterait un clonage explicite de chaque élément.
<?php
header("Content-type: text/plain");
class MaClasse {
private $monArray = array();
function metDansArray($var) {
array_push($this->monArray, $var);
}
function getArray() {
return $this->monArray;
}
}
$monObjet = new MaClasse();
$monObjet->metDansArray('bleu');
$monObjet->metDansArray('orange');
// Clone : le tableau est copié avec ses valeurs actuelles (bleu, orange)
$monObjetClone = clone $monObjet;
// Modifications post-clonage : chaque objet évolue de son côté
$monObjet->metDansArray('rouge');
$monObjetClone->metDansArray('vert');
print "objet d'origine :\n";
print_r($monObjet->getArray()); // bleu, orange, rouge
print "objet clone :\n";
print_r($monObjetClone->getArray()); // bleu, orange, vert
?>Résultat :
objet d'origine :
Array
(
[0] => bleu
[1] => orange
[2] => rouge
)
objet clone :
Array
(
[0] => bleu
[1] => orange
[2] => vert
)
Les deux tableaux ont divergé après le clonage : chacun contient sa propre couleur ajoutée en troisième position. Pas besoin de __clone() ici.
Bonnes pratiques en 2026
Le clonage sert principalement à implémenter le pattern Prototype, créer des snapshots d'état pour l'historique ou l'annulation, dupliquer des objets de configuration, ou travailler avec des Value Objects. Pour les objets qui encapsulent des ressources externes (connexion PDO, handle de fichier), pensez à les fermer ou réinitialiser dans __clone() — les partager entre deux instances crée des comportements imprévisibles. Le mécanisme est stable depuis PHP 5 et fonctionne sans modification sur PHP 8.3.
Par carabde | Mis à jour le 13 avril 2026