Objekt-Klonen im Detail
Teil des Abschnitts Objektorientierte Programmierung der PHP-Journey von Coddy — Lektion 61 von 91.
Sie haben bereits früher in diesem Kurs etwas über die magische Methode __clone gelernt. Lassen Sie uns nun den entscheidenden Unterschied zwischen flachem und tiefem Klonen untersuchen, wenn Objekte andere Objekte als Eigenschaften enthalten.
Standardmäßig führt PHP beim Klonen eine flache Kopie (shallow copy) aus. Skalare Werte werden dupliziert, aber Objekteigenschaften bleiben Referenzen auf dieselben Objekte:
<?php
class Address {
public function __construct(public string $city) {}
}
class Person {
public function __construct(
public string $name,
public Address $address
) {}
}
$original = new Person("Alice", new Address("Paris"));
$clone = clone $original;
$clone->name = "Bob";
$clone->address->city = "London";
echo $original->name . " - " . $original->address->city;
Ausgabe:
Alice - LondonBeachten Sie, dass das Ändern von $clone->name das Original nicht beeinflusst hat, aber das Ändern der Stadt in der Adresse schon! Beide Objekte teilen sich dieselbe Address-Instanz.
Um eine tiefe Kopie zu erstellen, bei der auch verschachtelte Objekte geklont werden, implementieren Sie __clone:
<?php
class Person {
public function __construct(
public string $name,
public Address $address
) {}
public function __clone(): void {
$this->address = clone $this->address;
}
}
$original = new Person("Alice", new Address("Paris"));
$clone = clone $original;
$clone->address->city = "London";
echo $original->address->city;
Ausgabe:
ParisNun hat jede Person ihre eigene unabhängige Address. Wenn Ihre Objekte mehrere verschachtelte Objekte enthalten, müssen Sie jedes einzelne in __clone klonen, um eine echte Unabhängigkeit zwischen dem Original und der Kopie zu erreichen.
Aufgabe
EinfachLass uns ein Dokumentenmanagementsystem erstellen, das den Unterschied zwischen flachem (shallow) und tiefem (deep) Klonen demonstriert. Du wirst Dokumente erstellen, die Autoreninformationen enthalten, und sicherstellen, dass das Klonen eines Dokuments eine wirklich unabhängige Kopie erstellt.
Du wirst deinen Code in drei Dateien organisieren:
Author.php— Erstelle eineAuthor-Klasse, die den Autor eines Dokuments repräsentiert. Verwende Constructor Promotion, um ein öffentliches$name(String) und ein öffentliches$email(String) zu definieren.Document.php— Erstelle eineDocument-Klasse, die einen Autor enthält. Binde die Author-Datei ein. Die Klasse sollte:- Constructor Promotion für ein öffentliches
$title(String) und ein öffentliches$author(Author) verwenden - Die magische Methode
__clone()implementieren, um tiefes Klonen (Deep Cloning) durchzuführen — wenn ein Dokument geklont wird, sollte auch sein Autor geklont werden, damit Änderungen am Autor des Klons das Original nicht beeinflussen - Eine Methode
getInfo()haben, die"[title] by [author name] ([author email])"zurückgibt
- Constructor Promotion für ein öffentliches
main.php— Binde die Document-Datei ein. Du erhältst drei Eingaben: einen Dokumententitel, einen Autorennamen und eine Autoren-E-Mail.Erstelle ein
Documentmit einemAuthorunter Verwendung der bereitgestellten Eingaben. Klone das Dokument, ändere dann den Autorennamen des Klons, indem du" (Copy)"anhängst, und ändere den Titel des Klons, indem du"Copy of "voranstellst.Gib zwei Zeilen aus:
- Die Informationen des Originaldokuments
- Die Informationen des geklonten Dokuments
Wenn dein Deep Cloning korrekt implementiert ist, sollte der Autor des Originaldokuments unverändert bleiben, selbst nachdem der Autor des Klons geändert wurde.
Diese Herausforderung zeigt, warum Deep Cloning wichtig ist — ohne eine ordnungsgemäße Implementierung von __clone() würden beide Dokumente dasselbe Author-Objekt teilen, und die Änderung des einen würde das andere beeinflussen.
Spickzettel
Standardmäßig führt PHP beim Klonen von Objekten eine flache Kopie (shallow copy) aus. Skalare Werte werden dupliziert, aber Objekteigenschaften bleiben Referenzen auf dieselben Objekte.
Beispiel für flaches Klonen:
<?php
class Address {
public function __construct(public string $city) {}
}
class Person {
public function __construct(
public string $name,
public Address $address
) {}
}
$original = new Person("Alice", new Address("Paris"));
$clone = clone $original;
$clone->name = "Bob";
$clone->address->city = "London";
echo $original->name . " - " . $original->address->city;
// Ausgabe: Alice - London
Das Ändern von $clone->name hat keine Auswirkungen auf das Original, aber das Ändern des verschachtelten address-Objekts schon, da beide Objekte dieselbe Address-Instanz teilen.
Um eine tiefe Kopie (deep copy) zu erstellen, bei der auch verschachtelte Objekte geklont werden, implementieren Sie die magische Methode __clone:
<?php
class Person {
public function __construct(
public string $name,
public Address $address
) {}
public function __clone(): void {
$this->address = clone $this->address;
}
}
$original = new Person("Alice", new Address("Paris"));
$clone = clone $original;
$clone->address->city = "London";
echo $original->address->city;
// Ausgabe: Paris
Wenn Objekte mehrere verschachtelte Objekte enthalten, müssen Sie jedes einzelne in __clone klonen, um eine echte Unabhängigkeit zwischen dem Original und der Kopie zu erreichen.
Probier es selbst
<?php
require_once 'Document.php';
// Eingaben lesen
$title = trim(fgets(STDIN));
$authorName = trim(fgets(STDIN));
$authorEmail = trim(fgets(STDIN));
// TODO: Erstellen Sie einen Autor mit dem angegebenen Namen und der E-Mail-Adresse
// TODO: Erstellen Sie ein Dokument mit dem angegebenen Titel und dem Autor
// TODO: Klonen Sie das Dokument
// TODO: Ändern Sie den Namen des Autors des Klons, indem Sie " (Copy)" anhängen
// TODO: Ändern Sie den Titel des Klons, indem Sie "Copy of " voranstellen
// TODO: Geben Sie die Informationen des Originaldokuments aus
// TODO: Geben Sie die Informationen des geklonten Dokuments aus
?>Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas $this-SchlüsselwortMethodenEigenschaftenKonstruktor (__construct)Destruktor (__destruct)Rückblick - Einfacher Taschenrechner4Vererbung
Grundlagen der VererbungDas parent:: SchlüsselwortMethoden überschreibenDas final SchlüsselwortAbstrakte KlassenZusammenfassung – Mitarbeiter-Hierarchie7Kapselung
Public, Protected, PrivateZugriffsmodifikatoren im DetailGetter und SetterInformation HidingConstructor Promotion (8.0)Zusammenfassung – Studentenverwaltungssystem10Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungDependency InjectionAnonyme KlassenEnums (PHP 8.1)Fibers (PHP 8.1)Objekt-Klonen im DetailGeneratoren & Iteratoren2Namensräume & Autoloading
Einführung in NamensräumeDas use-SchlüsselwortPSR-4 Autoloading-StandardComposer AutoloaderZusammenfassung – Organisiertes Projekt5Interfaces & Verträge
Einführung in InterfacesInterfaces implementierenMehrfache Interface-ImplementierungInterface vs. Abstrakte KlasseType Hinting mit InterfacesZusammenfassung – Formen-Rechner8Magische Methoden
Einführung in magische Methoden__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Objekt-Klonen__serialize & __unserializeZusammenfassung - Eigene Collection11Typsystem & Fehlerbehandlung
TypdeklarationenNullable-TypenUnion- & Intersection-TypenException-KlassenEigene Exception-HierarchieTry, Catch, FinallyZusammenfassung - Formular-Validator14Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen3Klasseneigenschaften
Instanz- vs. statische EigenschaftenKonstanten in KlassenStatische Methoden & EigenschaftenPrivate & geschützte EigenschaftenReadonly-Eigenschaften (PHP 8.1)Zusammenfassung – Bankkonto-Manager6Polymorphismus
Method Overriding erneut betrachtetPolymorphismus über InterfacesType Hinting & Union TypesLate Static BindingZusammenfassung – Payment Processor9Traits
Einführung in TraitsVerwendung mehrerer TraitsKonfliktlösung bei TraitsAbstrakte Methoden in TraitsTraits vs. Vererbung12Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster15Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung