Es ist eine lange, traurige Geschichte.
Als PHP 5.2 diese Warnung zum ersten Mal einführte, waren späte statische Bindungen noch nicht in der Sprache. Falls Sie mit späten statischen Bindungen nicht vertraut sind, beachten Sie, dass Code wie dieser nicht wie erwartet funktioniert:
<?php
abstract class ParentClass {
static function foo() {
echo "I'm gonna do bar()";
self::bar();
}
abstract static function bar();
}
class ChildClass extends ParentClass {
static function bar() {
echo "Hello, World!";
}
}
ChildClass::foo();
Abgesehen von der Warnung vor dem strengen Modus funktioniert der obige Code nicht. Der self::bar()
Aufruf in foo()
bezieht sich explizit auf die bar()
Methode von ParentClass
, auch wenn foo()
er als Methode von aufgerufen wird ChildClass
. Wenn Sie versuchen, diesen Code mit deaktiviertem Strict-Modus auszuführen, wird " Schwerwiegender PHP-Fehler: Abstrakte Methode ParentClass :: bar () kann nicht aufgerufen werden" angezeigt .
Vor diesem Hintergrund waren abstrakte statische Methoden in PHP 5.2 nutzlos. Der Sinn einer abstrakten Methode besteht darin, dass Sie Code schreiben können, der die Methode aufruft, ohne zu wissen, welche Implementierung aufgerufen werden soll, und dann verschiedene Implementierungen für verschiedene untergeordnete Klassen bereitstellen können. Da PHP 5.2 keine saubere Möglichkeit bietet, eine Methode einer übergeordneten Klasse zu schreiben, die eine statische Methode der untergeordneten Klasse aufruft, für die sie aufgerufen wird, ist diese Verwendung abstrakter statischer Methoden nicht möglich. Daher ist jede Verwendung abstract static
in PHP 5.2 ein schlechter Code, wahrscheinlich inspiriert durch ein Missverständnis der Funktionsweise des self
Schlüsselworts. Es war völlig vernünftig, eine Warnung darüber zu werfen.
Dann wurde PHP 5.3 hinzugefügt, um auf die Klasse zu verweisen, für die eine Methode über das static
Schlüsselwort aufgerufen wurde (im Gegensatz zum self
Schlüsselwort, das sich immer auf die Klasse bezieht, in der die Methode definiert wurde ). Wenn Sie ändern , self::bar()
um static::bar()
in meinem Beispiel oben, es funktioniert gut in PHP 5.3 und höher. Sie können mehr über self
vs static
bei New self vs. new static lesen .
Mit dem hinzugefügten statischen Schlüsselwort war das eindeutige Argument für das abstract static
Auslösen einer Warnung verschwunden. Der Hauptzweck von späten statischen Bindungen bestand darin, in einer übergeordneten Klasse definierten Methoden das Aufrufen statischer Methoden zu ermöglichen, die in untergeordneten Klassen definiert werden würden. Das Zulassen abstrakter statischer Methoden erscheint angesichts der späten statischen Bindungen vernünftig und konsistent.
Sie könnten immer noch dafür eintreten, die Warnung beizubehalten. Zum Beispiel könnte man argumentieren , dass seit PHP können Sie statische Methoden der abstrakten Klassen nennen, in meinem Beispiel oben (auch nachdem sie durch den Austausch Fixierung self
mit static
) Sie aussetzt eine öffentliche Methode , ParentClass::foo()
die ist gebrochen und dass Sie nicht wirklich wollen entlarven. Die Verwendung einer nicht statischen Klasse - das heißt, alle Methoden zu Instanzmethoden zu machen und die untergeordneten Methoden ParentClass
zu Singletons oder Ähnlichem zu machen - würde dieses Problem lösen, da ParentClass
sie abstrakt sind und daher nicht instanziiert werden können heißen. Ich denke, dieses Argument ist schwach (weil ich denke, es zu entlarvenParentClass::foo()
ist keine große Sache und die Verwendung von Singletons anstelle von statischen Klassen ist oft unnötig ausführlich und hässlich), aber Sie könnten einigermaßen anderer Meinung sein - es ist ein etwas subjektiver Aufruf.
Basierend auf diesem Argument haben die PHP-Entwickler die Warnung in der Sprache beibehalten, oder?
Äh, nicht genau .
Der oben verlinkte PHP-Fehlerbericht 53081 forderte das Löschen der Warnung, da das Hinzufügen des static::foo()
Konstrukts abstrakte statische Methoden sinnvoll und nützlich gemacht hatte. Rasmus Lerdorf (Schöpfer von PHP) kennzeichnet die Anfrage zunächst als falsch und durchläuft eine lange Kette von schlechten Argumenten, um zu versuchen, die Warnung zu rechtfertigen. Dann findet endlich dieser Austausch statt:
Giorgio
ich weiss aber:
abstract class cA
{
//static function A(){self::B();} error, undefined method
static function A(){static::B();} // good
abstract static function B();
}
class cB extends cA
{
static function B(){echo "ok";}
}
cB::A();
Rasmus
Genau so sollte es funktionieren.
Giorgio
aber es ist nicht erlaubt :(
Rasmus
Was ist nicht erlaubt?
abstract class cA {
static function A(){static::B();}
abstract static function B();
}
class cB extends cA {
static function B(){echo "ok";}
}
cB::A();
Das funktioniert gut. Sie können self :: B () natürlich nicht aufrufen, aber static :: B () ist in Ordnung.
Die Behauptung von Rasmus, dass der Code in seinem Beispiel "gut funktioniert", ist falsch; Wie Sie wissen, wird eine strenge Moduswarnung ausgegeben. Ich denke, er hat ohne eingeschalteten strengen Modus getestet. Unabhängig davon ließ ein verwirrter Rasmus die Anfrage fälschlicherweise als "Schwindel" geschlossen.
Und deshalb ist die Warnung immer noch in der Sprache. Dies ist möglicherweise keine ganz zufriedenstellende Erklärung - Sie sind wahrscheinlich hierher gekommen, in der Hoffnung, dass die Warnung rational begründet ist. Leider werden in der realen Welt Entscheidungen manchmal eher aus weltlichen Fehlern und schlechten Argumenten als aus rationalen Entscheidungen getroffen. Dies ist einfach eine dieser Zeiten.
Glücklicherweise hat der geschätzte Nikita Popov die Warnung aus der Sprache in PHP 7 als Teil von PHP RFC entfernt: E_STRICT-Benachrichtigungen neu klassifizieren . Letztendlich hat sich die Vernunft durchgesetzt, und sobald PHP 7 veröffentlicht ist, können wir alle glücklich nutzen, abstract static
ohne diese dumme Warnung zu erhalten.