__clone i klonowanie obiektów
Część sekcji Programowanie obiektowe ścieżki PHP w Coddy. Lekcja 48 z 91.
Gdy przypisujesz jeden obiekt do innej zmiennej w PHP, nie tworzysz kopii — obie zmienne wskazują na ten sam obiekt. Aby utworzyć rzeczywiście niezależną kopię, musisz użyć słowa kluczowego 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;
Wynik:
999.99 - 899.99Domyślnie PHP wykonuje płytką kopię — kopiuje bezpośrednio wszystkie wartości właściwości. Działa to dobrze w przypadku wartości skalarnych, ale obiekty znajdujące się wewnątrz Twojego obiektu nadal odwołują się do tej samej instancji. Metoda magiczna __clone() pozwala dostosować to zachowanie:
<?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;
Wynik:
Original: 101, Clone: 0Metoda __clone() jest wywoływana dla nowego obiektu po utworzeniu płytkiej kopii. To tutaj resetujesz identyfikatory, tworzysz nowe kopie zagnieżdżonych obiektów lub wykonujesz wszelkie niezbędne czynności porządkowe, aby klon był całkowicie niezależny.
Wyzwanie
ŁatwyZbudujmy system wersjonowania dokumentów, który pokazuje, jak klonowanie tworzy niezależne kopie oraz jak magiczna metoda __clone() pozwala dostosować zachowanie obiektu podczas klonowania.
Rozmieścisz swój kod w dwóch plikach:
Document.php: Utwórz klasęDocument, która reprezentuje wersjonowany dokument. Użyj promocji konstruktora, aby zdefiniować publiczne$title(ciąg znaków), publiczne$content(ciąg znaków) oraz publiczne$version(liczbę całkowitą, której wartość domyślna wynosi 1). Dodaj prywatną właściwość$createdAt, która przechowuje bieżący znacznik czasu (w konstruktorze użyjdate('Y-m-d H:i:s')). Twój dokument powinien zawierać:getCreatedAt(): zwraca znacznik czasu utworzenia__clone(): podczas klonowania dokumentu wersja powinna zwiększyć się o 1, a wartość$createdAtpowinna zostać ustawiona na bieżący znacznik czasu (klon to nowa wersja utworzona „teraz”)
main.php: Dołącz plik Document. Otrzymasz trzy dane wejściowe: tytuł, treść oraz nowy ciąg znaków z treścią dla sklonowanej wersji. Utwórz obiektDocumentz tytułem i treścią. Następnie sklonuj go, aby utworzyć nową wersję, i zaktualizuj treść klonu, ustawiając nowy ciąg znaków. Wypisz cztery wiersze:- Wersję oryginalnego dokumentu
- Wersję sklonowanego dokumentu
- Treść oryginalnego dokumentu
- Treść sklonowanego dokumentu
Ten system pokazuje, jak __clone() pozwala kontrolować przebieg klonowania. Oryginalny dokument zachowuje swoją wersję i czas utworzenia, a klon automatycznie staje się nową wersją z aktualnym znacznikiem czasu. To idealne rozwiązanie do śledzenia historii dokumentu, w której każdy klon reprezentuje nową rewizję.
Spróbuj swoich sił
<?php
require_once 'Document.php';
// Wczytaj dane wejściowe
$title = trim(fgets(STDIN));
$content = trim(fgets(STDIN));
$newContent = trim(fgets(STDIN));
// TODO: Utwórz obiekt Document z tytułem i treścią
// TODO: Sklonuj dokument, aby utworzyć nową wersję
// TODO: Zaktualizuj treść klonu, ustawiając ją na nowy ciąg znaków
// TODO: Wypisz cztery wiersze:
// 1. Wersja oryginalnego dokumentu
// 2. Wersja sklonowanego dokumentu
// 3. Treść oryginalnego dokumentu
// 4. Treść sklonowanego dokumentu
?>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ów2Przestrzenie 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