Late Static Binding
Teil des Abschnitts Objektorientierte Programmierung der PHP-Journey von Coddy — Lektion 36 von 91.
Wenn Sie self:: in einer Elternklasse verwenden, bezieht es sich immer auf die Klasse, in der es geschrieben wurde, und nicht auf die Klasse, die tatsächlich verwendet wird. Dies kann zu unerwartetem Verhalten bei der Vererbung führen. Späte statische Bindung (Late Static Binding) löst dieses Problem durch die Verwendung des Schlüsselworts static::.
Betrachten Sie dieses Beispiel, in dem self:: nicht wie erwartet funktioniert:
<?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();
Ausgabe:
ParentClass
ParentClassObwohl wir ChildClass::create() aufgerufen haben, haben wir ein ParentClass-Objekt erhalten, da self:: zur Kompilierzeit aufgelöst wird. Lassen Sie uns nun stattdessen static:: verwenden:
<?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();
Ausgabe:
ChildClass
ChildClassMit static:: wartet PHP bis zur Laufzeit, um zu bestimmen, welche Klasse verwendet werden soll. Dies wird als „späte“ Bindung bezeichnet, da die Entscheidung verzögert wird. Es ist essenziell für Factory-Methoden und jede statische Methode, die Vererbung berücksichtigen soll.
Wichtiger Punkt: Verwenden Sie static:: anstelle von self::, wenn Sie möchten, dass Kindklassen statisches Verhalten korrekt erben und anpassen.
Aufgabe
EinfachLassen Sie uns ein Modell-Registrierungssystem erstellen, das die Leistungsfähigkeit der späten statischen Bindung (Late Static Binding) demonstriert. Sie erstellen eine Basisklasse Model mit einer Factory-Methode, die Kindklassen erben können — und dank static:: wird jede Kindklasse korrekt Instanzen von sich selbst anstatt von der Elternklasse erstellen.
Sie werden Ihren Code in vier Dateien organisieren:
Model.php— Erstellen Sie eine BasisklasseModelmit einer geschützten statischen Eigenschaft$tableName, die auf"models"gesetzt ist. Fügen Sie eine statische Methodecreate()hinzu, dienew static()verwendet, um eine neue Instanz der Klasse zurückzugeben, die sie aufgerufen hat. Fügen Sie eine weitere statische MethodegetTable()hinzu, diestatic::$tableNamezurückgibt. Fügen Sie schließlich eine Methodedescribe()hinzu, die"[ClassName] from table [tableName]"unter Verwendung vonstatic::classundstatic::$tableNamezurückgibt.User.php— Erstellen Sie eine KlasseUser, dieModelerweitert. Binden Sie die Datei der Elternklasse ein. Überschreiben Sie die statische Eigenschaft$tableNamemit"users". Die Klasse erbt alle Methoden vonModelohne Änderungen.Product.php— Erstellen Sie eine KlasseProduct, dieModelerweitert. Binden Sie die Datei der Elternklasse ein. Überschreiben Sie die statische Eigenschaft$tableNamemit"products". Auch hier erbt die Klasse alle Methoden von der Elternklasse.main.php— Binden Sie sowohl die User- als auch die Product-Dateien ein. Verwenden Sie die geerbte Factory-Methodecreate(), um Instanzen von sowohlUserals auchProductzu erstellen. Rufen Sie für jede Instanzdescribe()auf und geben Sie das Ergebnis in einer eigenen Zeile aus. Geben Sie dann den Tabellennamen für jede Klasse mitUser::getTable()undProduct::getTable()aus, jeweils in einer eigenen Zeile.
Der Clou dabei ist, dass die Methoden create() und getTable() nur in der Elternklasse Model definiert sind, aber dennoch korrekt mit den Kindklassen funktionieren, da static:: die Bindung bis zur Laufzeit verzögert. Wenn Sie User::create() aufrufen, erstellt PHP eine User-Instanz — keine Model-Instanz —, weil static:: sich auf die Klasse bezieht, die tatsächlich aufgerufen wurde.
Ihre Ausgabe sollte vier Zeilen enthalten: die Beschreibung für die User-Instanz, die Beschreibung für die Product-Instanz, den User-Tabellennamen und den Product-Tabellennamen.
Spickzettel
Das Schlüsselwort self:: in einer Elternklasse bezieht sich immer auf die Klasse, in der es geschrieben wurde, aufgelöst zur Kompilierzeit. Späte statische Bindung (Late Static Binding) mit static:: löst die Referenz zur Laufzeit auf, was es Kindklassen ermöglicht, statisches Verhalten korrekt zu erben und anzupassen.
Verwendung von self:: (Bindung zur Kompilierzeit)
<?php
class ParentClass {
public static function create() {
return new self(); // Erzeugt immer ParentClass
}
public static function getClassName() {
return self::class; // Gibt immer "ParentClass" zurück
}
}
class ChildClass extends ParentClass {}
$obj = ChildClass::create(); // Gibt ParentClass-Instanz zurück
echo ChildClass::getClassName(); // Ausgabe: ParentClass
Verwendung von static:: (Bindung zur Laufzeit)
<?php
class ParentClass {
public static function create() {
return new static(); // Erzeugt eine Instanz der aufrufenden Klasse
}
public static function getClassName() {
return static::class; // Gibt den Namen der aufrufenden Klasse zurück
}
}
class ChildClass extends ParentClass {}
$obj = ChildClass::create(); // Gibt ChildClass-Instanz zurück
echo ChildClass::getClassName(); // Ausgabe: ChildClass
Wichtiger Punkt: Verwenden Sie static:: anstelle von self::, wenn Sie möchten, dass Kindklassen statisches Verhalten korrekt erben und anpassen können. Dies ist essenziell für Factory-Methoden und jede statische Methode, die Vererbung berücksichtigen soll.
Probier es selbst
<?php
require_once 'User.php';
require_once 'Product.php';
// TODO: Verwende die geerbte Factory-Methode create(), um eine User-Instanz zu erstellen
// TODO: Verwende die geerbte Factory-Methode create(), um eine Product-Instanz zu erstellen
// TODO: Rufe describe() für die User-Instanz auf und gib das Ergebnis aus
// TODO: Rufe describe() für die Product-Instanz auf und gib das Ergebnis aus
// TODO: Gib User::getTable() aus
// TODO: Gib Product::getTable() 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 die OOPKlassen vs. ObjekteDas $this-SchlüsselwortMethodenEigenschaftenKonstruktor (__construct)Destruktor (__destruct)Rückblick - Einfacher Taschenrechner4Vererbung
Grundlagen der VererbungDas parent:: SchlüsselwortMethoden überschreibenDas final SchlüsselwortAbstrakte KlassenZusammenfassung – Mitarbeiter-Hierarchie7Kapselung
Public, Protected, PrivateZugriffsmodifikatoren im DetailGetter und SetterInformation HidingConstructor Promotion (8.0)Zusammenfassung – Studentenverwaltungssystem2Namensräume & Autoloading
Einführung in NamensräumeDas use-SchlüsselwortPSR-4 Autoloading-StandardComposer AutoloaderZusammenfassung – Organisiertes Projekt5Interfaces & Verträge
Einführung in InterfacesInterfaces implementierenMehrfache Interface-ImplementierungInterface vs. Abstrakte KlasseType Hinting mit InterfacesZusammenfassung – Formen-Rechner8Magische Methoden
Einführung in magische Methoden__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Objekt-Klonen__serialize & __unserializeZusammenfassung - Eigene Collection11Typsystem & Fehlerbehandlung
TypdeklarationenNullable-TypenUnion- & Intersection-TypenException-KlassenEigene Exception-HierarchieTry, Catch, FinallyZusammenfassung - Formular-Validator14Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen3Klasseneigenschaften
Instanz- vs. statische EigenschaftenKonstanten in KlassenStatische Methoden & EigenschaftenPrivate & geschützte EigenschaftenReadonly-Eigenschaften (PHP 8.1)Zusammenfassung – Bankkonto-Manager6Polymorphismus
Method Overriding erneut betrachtetPolymorphismus über InterfacesType Hinting & Union TypesLate Static BindingZusammenfassung – Payment Processor9Traits
Einführung in TraitsVerwendung mehrerer TraitsKonfliktlösung bei TraitsAbstrakte Methoden in TraitsTraits vs. Vererbung12Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster15Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung