Późne wiązanie statyczne
Część sekcji Programowanie obiektowe ścieżki PHP w Coddy. Lekcja 36 z 91.
Gdy używasz self:: w klasie nadrzędnej, zawsze odnosi się ono do klasy, w której zostało zapisane, a nie do klasy, która jest faktycznie używana. Może to powodować nieoczekiwane zachowanie w dziedziczeniu. Późne wiązanie statyczne rozwiązuje ten problem za pomocą słowa kluczowego static::.
Rozważmy ten przykład, w którym self:: nie działa zgodnie z oczekiwaniami:
<?php
class ParentClass {
public static function create() {
return new self();
}
public static function getClassName() {
return self::class;
}
}
class ChildClass extends ParentClass {}
$obj = ChildClass::create();
echo get_class($obj) . "\n";
echo ChildClass::getClassName();
Wynik:
ParentClass
ParentClassMimo że wywołaliśmy ChildClass::create(), otrzymaliśmy obiekt ParentClass, ponieważ self:: jest rozstrzygane podczas kompilacji. Teraz użyjmy zamiast tego static:::
<?php
class ParentClass {
public static function create() {
return new static();
}
public static function getClassName() {
return static::class;
}
}
class ChildClass extends ParentClass {}
$obj = ChildClass::create();
echo get_class($obj) . "\n";
echo ChildClass::getClassName();
Wynik:
ChildClass
ChildClassW przypadku static:: PHP czeka do czasu wykonania, aby określić, której klasy użyć. Nazywa się to „późnym” wiązaniem, ponieważ decyzja jest opóźniona. Jest to niezbędne w przypadku metod fabrykujących i każdej metody statycznej, która powinna uwzględniać dziedziczenie.
Kluczowa kwestia: Używaj static:: zamiast self::, gdy chcesz, aby klasy potomne poprawnie dziedziczyły i dostosowywały zachowanie statyczne.
Wyzwanie
ŁatwyZbudujmy system rejestru modeli, który pokazuje możliwości późnego wiązania statycznego. Utworzysz bazową klasę Model z metodą fabrykującą, którą mogą dziedziczyć klasy potomne, a dzięki static:: każda klasa potomna będzie poprawnie tworzyć swoje własne instancje, a nie instancje klasy nadrzędnej.
Rozmieścisz kod w czterech plikach:
Model.php: Utwórz bazową klasęModelz chronioną właściwością statyczną$tableNameustawioną na"models". Dodaj metodę statycznącreate(), która używanew static(), aby zwrócić nową instancję dowolnej klasy, która ją wywołała. Dodaj kolejną metodę statycznągetTable(), która zwracastatic::$tableName. Na koniec dodaj metodędescribe(), która zwraca"[ClassName] from table [tableName]", używającstatic::classistatic::$tableName.User.php: Utwórz klasęUser, która rozszerzaModel. Dołącz plik klasy nadrzędnej. Nadpisz statyczną właściwość$tableName, ustawiając ją na"users". Klasa dziedziczy wszystkie metody zModelbez żadnych zmian.Product.php: Utwórz klasęProduct, która rozszerzaModel. Dołącz plik klasy nadrzędnej. Nadpisz statyczną właściwość$tableName, ustawiając ją na"products". Klasa również dziedziczy wszystkie metody z klasy nadrzędnej.main.php: Dołącz pliki klas User i Product. Użyj odziedziczonej metody fabrykującejcreate(), aby utworzyć instancje zarównoUser, jak iProduct. Dla każdej instancji wywołajdescribe()i wyświetl wynik w osobnym wierszu. Następnie wyświetl nazwę tabeli dla każdej klasy, używającUser::getTable()iProduct::getTable(), każdą w osobnym wierszu.
Cała magia polega na tym, że metody create() i getTable() są zdefiniowane wyłącznie w nadrzędnej klasie Model, a mimo to poprawnie działają z klasami potomnymi, ponieważ static:: opóźnia wiązanie do czasu wykonania programu. Gdy wywołasz User::create(), PHP utworzy instancję klasy User, a nie Model, ponieważ static:: odnosi się do klasy, która faktycznie została wywołana.
Wynik powinien zawierać cztery wiersze: opis instancji User, opis instancji Product, nazwę tabeli User oraz nazwę tabeli Product.
Spróbuj swoich sił
<?php
require_once 'User.php';
require_once 'Product.php';
// TODO: Użyj odziedziczonej metody fabrykującej create(), aby utworzyć instancję User
// TODO: Użyj odziedziczonej metody fabrykującej create(), aby utworzyć instancję Product
// TODO: Wywołaj describe() na instancji User i wypisz wynik
// TODO: Wywołaj describe() na instancji Product i wypisz wynik
// TODO: Wypisz wynik User::getTable()
// TODO: Wypisz wynik Product::getTable()
?>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