__clone & Clonage d'objets
Fait partie de la section Programmation Orientée Objet du Journey PHP de Coddy — leçon 48 sur 91.
Lorsque vous affectez un objet à une autre variable en PHP, vous ne créez pas de copie - les deux variables pointent vers le même objet. Pour créer une copie réelle et indépendante, vous devez utiliser le mot-clé clone :
<?php
class Product {
public function __construct(
public string $name,
public float $price
) {}
}
$original = new Product("Laptop", 999.99);
$copy = clone $original;
$copy->price = 899.99;
echo $original->price . " - " . $copy->price;
Sortie :
999.99 - 899.99Par défaut, PHP effectue une copie superficielle - il copie directement toutes les valeurs des propriétés. Cela fonctionne bien pour les valeurs scalaires, mais les objets à l'intérieur de votre objet font toujours référence à la même instance. La méthode magique __clone() vous permet de personnaliser ce comportement :
<?php
class Order {
public function __construct(
public int $id,
public array $items = []
) {}
public function __clone(): void {
$this->id = 0;
$this->items = [];
}
}
$order1 = new Order(101, ["Book", "Pen"]);
$order2 = clone $order1;
echo "Original: " . $order1->id . ", Clone: " . $order2->id;
Sortie :
Original: 101, Clone: 0La méthode __clone() est appelée sur le nouvel objet après que la copie superficielle (shallow copy) a été effectuée. C'est ici que vous réinitialisez les IDs, créez de nouvelles copies des objets imbriqués ou effectuez tout nettoyage nécessaire pour que le clone soit véritablement indépendant.
Défi
FacileConstruisons un système de versionnage de documents qui démontre comment le clonage crée des copies indépendantes et comment la méthode magique __clone() vous permet de personnaliser ce qui se passe lorsqu'un objet est cloné.
Vous organiserez votre code sur deux fichiers :
Document.php— Créez une classeDocumentqui représente un document versionné. Utilisez la promotion de constructeur pour définir un$titlepublic (string), un$contentpublic (string), et un$versionpublic (integer, avec une valeur par défaut de 1). Ajoutez une propriété privée$createdAtqui stocke l'horodatage actuel (utilisezdate('Y-m-d H:i:s')dans le constructeur). Votre document a besoin de :getCreatedAt()— retourne l'horodatage de création__clone()— lorsqu'un document est cloné, la version doit être incrémentée de 1, et le$createdAtdoit être réinitialisé à l'horodatage actuel (le clone est une nouvelle version créée "maintenant")
main.php— Incluez le fichier Document. Vous recevrez trois entrées : un titre, un contenu, et une nouvelle chaîne de contenu pour la version clonée. Créez unDocumentavec le titre et le contenu. Ensuite, clonez-le pour créer une nouvelle version, et mettez à jour le contenu du clone avec la nouvelle chaîne de contenu. Affichez quatre lignes :- La version du document original
- La version du document cloné
- Le contenu du document original
- Le contenu du document cloné
Ce système montre comment __clone() vous permet de contrôler ce qui se passe pendant le clonage. Le document original conserve sa version et son heure de création, tandis que le clone devient automatiquement une nouvelle version avec un horodatage frais — parfait pour suivre l'historique des documents où chaque clone représente une nouvelle révision.
Aide-mémoire
Pour créer une copie indépendante d'un objet, utilisez le mot-clé clone :
<?php
class Product {
public function __construct(
public string $name,
public float $price
) {}
}
$original = new Product("Laptop", 999.99);
$copy = clone $original;
$copy->price = 899.99;
echo $original->price . " - " . $copy->price;
// Sortie : 999.99 - 899.99
Par défaut, PHP effectue une copie superficielle de toutes les valeurs de propriété. Pour personnaliser le comportement de clonage, utilisez la méthode magique __clone() :
<?php
class Order {
public function __construct(
public int $id,
public array $items = []
) {}
public function __clone(): void {
$this->id = 0;
$this->items = [];
}
}
$order1 = new Order(101, ["Book", "Pen"]);
$order2 = clone $order1;
echo "Original: " . $order1->id . ", Clone: " . $order2->id;
// Sortie : Original: 101, Clone: 0
La méthode __clone() est appelée sur le nouvel objet après la création de la copie superficielle, vous permettant de réinitialiser des propriétés ou de créer des copies indépendantes d'objets imbriqués.
Essayez vous-même
<?php
require_once 'Document.php';
// Lire les entrées
$title = trim(fgets(STDIN));
$content = trim(fgets(STDIN));
$newContent = trim(fgets(STDIN));
// TODO: Créer un Document avec le titre et le contenu
// TODO: Cloner le document pour créer une nouvelle version
// TODO: Mettre à jour le contenu du clone avec la nouvelle chaîne de contenu
// TODO: Afficher quatre lignes :
// 1. La version du document original
// 2. La version du document cloné
// 3. Le contenu du document original
// 4. Le contenu du document cloné
?>Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Les bases de la POO
Fichiers externesIntroduction à la POOClasses vs ObjetsLe mot-clé $thisMéthodesPropriétésConstructeur (__construct)Destructeur (__destruct)Récapitulatif - Calculatrice simple4Héritage
Héritage de baseLe mot-clé parent::Redéfinition de méthodeLe mot-clé finalClasses abstraitesRécapitulatif - Hiérarchie des employés7Encapsulation
Public, Protégé, PrivéModificateurs d'accès en détailGetters et SettersMasquage d'informationPromotion de constructeur (8.0)Récapitulatif - Système de gestion d'étudiants10Concepts avancés de la POO
Composition vs HéritageInjection de dépendancesClasses anonymesÉnumérations (PHP 8.1)Fibers (PHP 8.1)Clonage d'objets : analyse approfondieGénérateurs et Itérateurs13Patrons de conception Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode ModèlePatron ÉtatPatron CompositePatron Repository2Espaces de noms et Autoloading
Introduction aux espaces de nomsLe mot-clé useStandard d'Autoloading PSR-4L'Autoloader ComposerRécapitulatif - Projet organisé5Interfaces et Contrats
Introduction aux InterfacesImplémentation d'InterfacesImplémentation d'Interfaces MultiplesInterface vs Classe AbstraiteType Hinting avec les InterfacesRécapitulatif - Calculateur de Formes8Méthodes magiques
Introduction aux méthodes magiques__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Clonage d'objets__serialize & __unserializeRécapitulatif - Collection personnalisée3Propriétés de classe
Propriétés d'instance vs Propriétés statiquesConstantes dans les classesMéthodes et propriétés statiquesPropriétés privées et protégéesPropriétés readonly (PHP 8.1)Récapitulatif - Gestionnaire de compte bancaire6Polymorphisme
Retour sur la redéfinition de méthodePolymorphisme via les interfacesType Hinting et Types d'unionLiaison statique tardiveRécapitulatif - Processeur de paiement9Traits
Introduction aux TraitsUtilisation de plusieurs TraitsRésolution des conflits de TraitsMéthodes abstraites dans les TraitsTraits vs Héritage12Patrons de conception Partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FabriquePatron ObservateurPatron Stratégie