W PHP klasa dziedziczy po innej przez extends: class Dog extends Animal daje Dog każdą publiczną i chronioną właściwość oraz metodę Animal. Potomek może dodawać nowe metody, nadpisywać odziedziczone, deklarując metodę o tej samej nazwie, i wywoływać oryginał przez parent::method().
Dog nie ma konstruktora, więc używa konstruktora Animal, dlatego new Dog('Rex') działa. Klasa potomna może rozszerzać tylko jednego rodzica; PHP nie ma wielodziedziczenia klas.
Wywołanie metody rodzica przez parent::
Nadpisanie całkowicie zastępuje metodę rodzica. Aby ją rozszerzyć zamiast zastępować, wywołaj parent::method() z potomka i zbuduj coś na jej wyniku:
To samo działa dla konstruktorów przez parent::__construct(...), co opisuje strona o konstruktorze, łącznie z tym, co się dzieje, gdy o tym zapomnisz.
protected vs private w klasach potomnych
Element protected jest ukryty przed kodem zewnętrznym, ale widoczny dla każdej klasy w rodzinie. Element private jest widoczny tylko w klasie, która go deklaruje, więc klasa potomna w ogóle go nie widzi:
isset($this->pin) daje w potomku fałsz, bo potomek nie ma dostępu do prywatnego $pin rodzica, a własna metoda rodzica hasPin() nadal go czyta. Używaj protected dla tego, na czym podklasy mają budować, a private dla szczegółów, które chcesz móc swobodnie zmieniać.
Polimorfizm i instanceof
Kod napisany dla typu rodzica działa z każdym potomkiem. Każdy obiekt wykonuje własną wersję nadpisanej metody, więc jedna pętla obsługuje je wszystkie. instanceof sprawdza, czy obiekt jest danej klasy albo któregoś z jej potomków:
Gdy rodzic nigdy nie powinien być używany samodzielnie (zwykły Shape o polu 0 ma mało sensu), uczyń go klasą abstrakcyjną i zadeklaruj area() jako abstrakcyjną.
Zasady nadpisywania: sygnatury muszą pozostać zgodne
Nadpisująca metoda musi przyjmować co najmniej to, co przyjmował rodzic, i zwracać coś, czego mogą użyć wywołujący rodzica. Możesz dodać parametr opcjonalny, poszerzyć typ parametru albo zawęzić typ zwracany; nie możesz dodać wymaganego parametru ani uczynić metody publicznej prywatną.
Zmień string $sep = ',' na wymagane string $sep, a PHP odmówi skompilowania klasy z błędem krytycznym („Declaration of CsvExporter::export(array sep): string must be compatible with Exporter::export(array $rows): string”).
Klasy i metody final
final zatrzymuje dziedziczenie w tym miejscu. Metody final nie można nadpisać, a final class nie można rozszerzyć. Oba przypadki są sprawdzane przy kompilacji pliku, więc skrypt w ogóle się nie uruchamia:
<?php
class Payment
{
final public function charge(int $cents): string
{
return "charged $cents";
}
}
class FreePayment extends Payment
{
public function charge(int $cents): string
{
return 'free';
}
}
PHP Fatal error: Cannot override final method Payment::charge() in /home/index.php on line 12
Dla klasy final komunikat to Class B cannot extend final class A. Oznacz metodę jako final, gdy rodzic polega na tym, że działa ona dokładnie w jeden sposób, na przykład metoda sprawdzająca uprawnienia przed zrobieniem czegokolwiek innego.
Pułapka z metodami prywatnymi
Metoda prywatna nie jest dziedziczona, więc metoda potomka o tej samej nazwie jej nie nadpisuje. Kod w rodzicu nadal wywołuje własną prywatną wersję, co zaskakuje osoby, które spodziewają się wykonania metody potomka:
greet() nadal wypisuje Hello: $this->word() w rodzicu wskazuje na prywatną metodę rodzica. Zmień private na protected w Greeter i uruchom ponownie; teraz metoda potomka jest prawdziwym nadpisaniem, a greet() mówi Bonjour.
Najczęściej zadawane pytania
Jak działa extends w PHP?
class Dog extends Animal czyni Dog potomkiem Animal. Obiekt Dog ma każdą publiczną i chronioną właściwość oraz metodę Animal, może dodać własne i zastąpić (nadpisać) odziedziczone metody, deklarując metodę o tej samej nazwie.
Jak wywołać metodę rodzica w PHP?
Użyj parent::methodName() w metodzie potomka, na przykład return parent::describe() . ' and more';. Dla konstruktora jest to parent::__construct(...).
Czy PHP obsługuje wielodziedziczenie?
Nie. Klasa może rozszerzać tylko jedną klasę rodzica. Aby współdzielić zachowanie z kilku źródeł, implementuj kilka interfejsów (class A implements B, C) i używaj traitów (use Loggable, Timestamps;).
Co oznacza final w PHP?
Metody final nie można nadpisać w klasie potomnej, a final class nie można w ogóle rozszerzyć. Złamanie którejkolwiek zasady to błąd krytyczny przy kompilacji klasy, na przykład Cannot override final method A::f().
Czy klasa potomna ma dostęp do prywatnej właściwości rodzica w PHP?
Nie. Element private należy tylko do klasy, która go deklaruje, więc w potomku $this->pin to niezdefiniowana właściwość (ostrzeżenie, a potem null), a metoda potomka o tej samej nazwie nie nadpisuje prywatnej. Zadeklaruj element jako protected, gdy potrzebują go klasy potomne.