Objektklonen im Detail
Teil des Abschnitts Objektorientierte Programmierung der PHP-Journey von Coddy. Lektion 61 von 91.
Du hast die magische __clone-Methode bereits früher in diesem Kurs kennengelernt. Sehen wir uns nun den entscheidenden Unterschied zwischen flachem und tiefem Klonen an, wenn Objekte andere Objekte als Eigenschaften enthalten.
Standardmäßig führt PHP beim Klonen eine flache Kopie durch. Skalare Werte werden dupliziert, aber Objekteigenschaften bleiben Verweise 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 - LondonBeachte, dass das Ändern von $clone->name das Original nicht beeinflusst hat, aber das Ändern der Adressstadt schon! Beide Objekte verwenden dieselbe Address-Instanz.
Um eine tiefe Kopie zu erstellen, bei der verschachtelte Objekte ebenfalls geklont werden, implementiere __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:
ParisJetzt hat jede Person ihre eigene unabhängige Address. Wenn deine Objekte mehrere verschachtelte Objekte enthalten, musst du jedes einzelne in __clone klonen, um eine echte Unabhängigkeit zwischen dem Original und der Kopie zu erreichen.
Aufgabe
EinfachLass uns ein Dokumentverwaltungssystem erstellen, das den Unterschied zwischen flachem und tiefem 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 auf drei Dateien verteilen:
Author.php: Erstelle eineAuthor-Klasse, die den Autor eines Dokuments repräsentiert. Verwende Konstruktor-Promotion, um einen öffentlichen$name(String) und eine öffentliche$email(String) zu definieren.Document.php: Erstelle eineDocument-Klasse, die einen Autor enthält. Binde die Author-Datei ein. Die Klasse sollte:- Konstruktor-Promotion für einen öffentlichen
$title(String) und einen öffentlichen$author(Author) verwenden - die magische Methode
__clone()implementieren, um tiefes Klonen durchzuführen; wenn ein Dokument geklont wird, sollte auch sein Autor geklont werden, damit Änderungen am Autor der Kopie das Original nicht beeinflussen - eine Methode
getInfo()besitzen, die"[title] by [author name] ([author email])"zurückgibt
- Konstruktor-Promotion für einen öffentlichen
main.php: Binde die Document-Datei ein. Du erhältst drei Eingaben: einen Dokumenttitel, einen Autorennamen und eine E-Mail-Adresse des Autors.Erstelle mit den bereitgestellten Eingaben ein
Documentmit einemAuthor. Klone das Dokument anschließend, füge dann an den Autorennamen der Kopie" (Copy)"an und stelle dem Titel der Kopie"Copy of "voran.Gib zwei Zeilen aus:
- Die Informationen des Originaldokuments
- Die Informationen des geklonten Dokuments
Wenn dein tiefes Klonen korrekt implementiert ist, sollte der Autor des Originaldokuments auch nach der Änderung des Autors der Kopie unverändert bleiben.
Diese Herausforderung zeigt, warum tiefes Klonen wichtig ist: Ohne eine ordnungsgemäße Implementierung von __clone() würden beide Dokumente dasselbe Author-Objekt gemeinsam nutzen, und eine Änderung an einem Dokument würde sich auf das andere auswirken.
Probier es selbst
<?php
require_once 'Document.php';
// Eingaben lesen
$title = trim(fgets(STDIN));
$authorName = trim(fgets(STDIN));
$authorEmail = trim(fgets(STDIN));
// TODO: Erstelle einen Author mit dem angegebenen Namen und der E-Mail
// TODO: Erstelle ein Document mit dem angegebenen Titel und dem Author
// TODO: Klone das Dokument
// TODO: Ändere den Autorennamen des Klons, indem du " (Copy)" anhängst
// TODO: Ändere den Titel des Klons, indem du "Copy of " voranstellst
// TODO: Gib die Infos des Originaldokuments aus
// TODO: Gib die Infos 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 OOPKlassen vs. ObjekteDas Schlüsselwort $thisMethodenEigenschaftenKonstruktor (__construct)Destruktor (__destruct)Rückblick – Einfacher Taschenrechner4Vererbung
Grundlegende VererbungDas Schlüsselwort parent::MethodenüberschreibungDas Schlüsselwort finalAbstrakte KlassenRückblick – Mitarbeiterhierarchie7Kapselung
Öffentlich, geschützt, privatZugriffsmodifikatoren im DetailGetter und SetterInformationsverbergungKonstruktor-Promotion (8.0)Wiederholung – System zur Verwaltung von Schülerdatensätzen10Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungDependency InjectionAnonyme KlassenEnums (PHP 8.1)Fibers (PHP 8.1)Objektklonen im DetailGeneratoren & Iteratoren2Namespaces & Autoloading
Einführung in NamespacesDas use-SchlüsselwortPSR-4-Autoloading-StandardComposer-AutoloaderRückblick – Organisiertes Projekt5Schnittstellen & Verträge
Einführung in SchnittstellenSchnittstellen implementierenMehrere Schnittstellen implementierenSchnittstelle vs. abstrakte KlasseTyp-Hinweise mit SchnittstellenRückblick – Formrechner8Magische Methoden
Einführung in magische Methoden__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Objektklonen__serialize & __unserializeRückblick – Benutzerdefinierte Sammlung11Typsystem & Fehlerbehandlung
TypdeklarationenNullable-TypenUnion- & Intersection-TypenException-KlassenBenutzerdefinierte Exception-HierarchieTry, Catch, FinallyRückblick – Formularvalidator14Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen3Klassen-Eigenschaften
Instanz- vs. statische EigenschaftenKonstanten in KlassenStatische Methoden & EigenschaftenPrivate & geschützte EigenschaftenSchreibgeschützte Eigenschaften (PHP 8.1)Zusammenfassung – Bankkonto-Manager6Polymorphie
Methodenüberschreibung erneut betrachtetPolymorphie über SchnittstellenTyp-Hinweise & Union-TypenSpätes statisches BindenRückblick – Zahlungsabwickler9Traits
Einführung in TraitsMehrere Traits verwendenAuflösung von Trait-KonfliktenAbstrakte Methoden in TraitsTraits vs. Vererbung12Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster15Abschließende Herausforderungen
E-Learning-PlattformBankingsystemEntwicklung einer SpielfigurFahrzeugvermietungÜbe selbstständig: Online-PHP-Compiler