Dogłębne omówienie klonowania obiektów
Część sekcji Programowanie obiektowe ścieżki PHP w Coddy. Lekcja 61 z 91.
Wcześniej w tym kursie poznano magiczną metodę __clone. Teraz przyjrzyjmy się kluczowej różnicy między klonowaniem płytkim a głębokim, gdy obiekty zawierają inne obiekty jako właściwości.
Domyślnie podczas klonowania PHP wykonuje płytką kopię. Wartości skalarne są duplikowane, ale właściwości obiektów pozostają referencjami do tych samych obiektów:
<?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;
Wynik:
Alice - LondonZauważ, że zmiana $clone->name nie wpłynęła na oryginał, ale zmiana miasta w adresie już tak! Oba obiekty współdzielą tę samą instancję Address.
Aby utworzyć głęboką kopię, w której zagnieżdżone obiekty również są klonowane, zaimplementuj __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;
Wynik:
ParisTeraz każda Person ma własny, niezależny obiekt Address. Gdy obiekty zawierają wiele zagnieżdżonych obiektów, musisz sklonować każdy z nich w __clone, aby zapewnić pełną niezależność oryginału i kopii.
Wyzwanie
ŁatwyStwórzmy system zarządzania dokumentami, który pokazuje różnicę między płytkim a głębokim klonowaniem. Utworzysz dokumenty zawierające informacje o autorze i zadbasz o to, by sklonowanie dokumentu tworzyło naprawdę niezależną kopię.
Rozmieścisz swój kod w trzech plikach:
Author.php: Utwórz klasęAuthor, która reprezentuje autora dokumentu. Użyj promocji konstruktora, aby zdefiniować publiczne$name(string) i publiczne$email(string).Document.php: Utwórz klasęDocument, która zawiera autora. Dołącz plik Author. Klasa powinna:- Użyć promocji konstruktora dla publicznego
$title(string) i publicznego$author(Author) - Zaimplementować magiczną metodę
__clone(), aby wykonywać głębokie klonowanie; gdy dokument jest klonowany, jego autor również powinien zostać sklonowany, tak aby zmiany w autorze kopii nie wpływały na oryginał - Mieć metodę
getInfo(), która zwraca"[title] by [author name] ([author email])"
- Użyć promocji konstruktora dla publicznego
main.php: Dołącz plik Document. Otrzymasz trzy dane wejściowe: tytuł dokumentu, imię i nazwisko autora oraz adres e-mail autora.Utwórz obiekt
Documentz obiektemAuthor, korzystając z podanych danych wejściowych. Sklonuj dokument, a następnie zmodyfikuj imię i nazwisko autora kopii, dopisując do niego" (Copy)", i zmień tytuł kopii, dodając na początku"Copy of ".Wypisz dwa wiersze:
- Informacje o oryginalnym dokumencie
- Informacje o sklonowanym dokumencie
Jeśli głębokie klonowanie jest zaimplementowane poprawnie, autor oryginalnego dokumentu powinien pozostać bez zmian nawet po zmodyfikowaniu autora kopii.
To wyzwanie pokazuje, dlaczego głębokie klonowanie jest ważne. Bez prawidłowej implementacji __clone() oba dokumenty współdzieliłyby ten sam obiekt Author, a zmiana jednego wpłynęłaby na drugi.
Spróbuj swoich sił
<?php
require_once 'Document.php';
// Odczytaj dane wejściowe
$title = trim(fgets(STDIN));
$authorName = trim(fgets(STDIN));
$authorEmail = trim(fgets(STDIN));
// TODO: Utwórz obiekt Author z podanym imieniem i nazwiskiem oraz adresem e-mail
// TODO: Utwórz obiekt Document z podanym tytułem i obiektem Author
// TODO: Sklonuj dokument
// TODO: Zmień imię i nazwisko autora klonu, dopisując na końcu " (Copy)"
// TODO: Zmień tytuł klonu, dodając na początku "Copy of "
// TODO: Wyświetl informacje o oryginalnym dokumencie
// TODO: Wyświetl informacje o sklonowanym dokumencie
?>Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneWprowadzenie do programowania obiektowegoKlasy a obiektySłowo kluczowe $thisMetodyWłaściwościKonstruktor (__construct)Destruktor (__destruct)Powtórka — prosty kalkulator4Dziedziczenie
Podstawy dziedziczeniaSłowo kluczowe parent::Przesłanianie metodSłowo kluczowe finalKlasy abstrakcyjnePowtórzenie – hierarchia pracowników7Enkapsulacja
Public, protected, privateModyfikatory dostępu w szczegółachGettery i setteryUkrywanie informacjiPromocja parametrów konstruktora (8.0)Podsumowanie — system ewidencji studentów10Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieWstrzykiwanie zależnościKlasy anonimoweEnumy (PHP 8.1)Włókna (PHP 8.1)Dogłębne omówienie klonowania obiektówGeneratory i iteratory2Przestrzenie nazw i autoloading
Wprowadzenie do przestrzeni nazwSłowo kluczowe useStandard autoloadingu PSR-4Autoloader ComposeraPodsumowanie – uporządkowany projekt5Interfejsy i kontrakty
Wprowadzenie do interfejsówImplementowanie interfejsówImplementowanie wielu interfejsówInterfejs a klasa abstrakcyjnaPodpowiadanie typów za pomocą interfejsówPodsumowanie — kalkulator kształtów8Metody magiczne
Wprowadzenie do metod magicznych__toString i __debugInfo__get, __set, __isset, __unset__call i __callStatic__clone i klonowanie obiektów__serialize i __unserializePodsumowanie — własna kolekcja11System typów i obsługa błędów
Deklaracje typówTypy nullableTypy sumy i przecięciaKlasy wyjątkówNiestandardowa hierarchia wyjątkówTry, Catch, FinallyPodsumowanie — walidator formularzy14Projekt: Zarządzanie biblioteką
Przegląd projektuKlasy książki i użytkownika3Właściwości klas
Właściwości instancji a właściwości statyczneStałe w klasachMetody i właściwości statyczneWłaściwości prywatne i chronioneWłaściwości tylko do odczytu (PHP 8.1)Podsumowanie — menedżer kont bankowych6Polimorfizm
Ponowne omówienie nadpisywania metodPolimorfizm za pomocą interfejsówPodpowiedzi typów i typy sumyPóźne wiązanie statycznePodsumowanie — procesor płatności9Cechy
Wprowadzenie do cechKorzystanie z wielu cechRozwiązywanie konfliktów cechMetody abstrakcyjne w cechachCechy a dziedziczenie12Wzorce projektowe, część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec ObserverWzorzec StrategyPoćwicz samodzielnie: Kompilator PHP online