長くて悲しい話です。
PHP 5.2 でこの警告が最初に導入されたとき、言語にはまだ遅延静的バインディングがありませんでした。遅延静的バインディングに慣れていない場合は、次のようなコードが期待どおりに機能しないことに注意してください。
<?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();
厳密モードの警告は別として、上記のコードは機能しません。のself::bar()
呼び出しは、 が のメソッドとして呼び出される場合でも、 のメソッドをfoo()
明示的に参照します。厳密モードをオフにしてこのコードを実行しようとすると、「PHP Fatal error: Cannot call abstract method ParentClass::bar()」が表示されます。bar()
ParentClass
foo()
ChildClass
このため、PHP 5.2 の抽象静的メソッドは役に立ちませんでした。抽象メソッドを使用することの全体的なポイントは、メソッドが呼び出す実装を知らなくてもメソッドを呼び出すコードを記述し、異なる子クラスに異なる実装を提供できることです。しかし、PHP 5.2 には、呼び出された子クラスの静的メソッドを呼び出す親クラスのメソッドを記述する明確な方法がないため、抽象静的メソッドをこのように使用することはできません。したがってabstract static
、PHP 5.2 での の使用はすべて悪いコードであり、おそらくself
キーワードがどのように機能するかについての誤解に触発されたものです。これについて警告を発することは完全に合理的でした。
しかし、PHP 5.3 では、メソッドが呼び出されたクラスをキーワードで参照する機能が追加されました(メソッドが定義されたクラスを常に参照するキーワードstatic
とは異なります)。上記の例を に変更すると、PHP 5.3 以降で正常に動作します。vsの詳細については、New self vs. new staticを参照してください。self
self::bar()
static::bar()
self
static
abstract static
static キーワードが追加されたことで、警告をスローする明確な理由がなくなりました。後期静的バインディングの主な目的は、親クラスで定義されたメソッドが、子クラスで定義される静的メソッドを呼び出せるようにすることでした。抽象静的メソッドを許可することは、後期静的バインディングが存在することを考えると、合理的で一貫しているように見えます。
それでも、警告を維持することを主張することはできると思います。たとえば、PHP では抽象クラスの静的メソッドを呼び出すことができるため、上記の例では ( に置き換えself
て修正した後でも)、壊れたパブリック メソッドをstatic
公開していて、実際にはそうしたくないと主張することができます。公開。非静的クラスを使用する - つまり、すべてのメソッドをインスタンス メソッドにし、すべての子をシングルトンか何かにする - はこの問題を解決します。呼ばれます。この議論は弱いと思います(ParentClass::foo()
ParentClass
ParentClass
ParentClass::foo()
大したことではなく、静的クラスの代わりにシングルトンを使用することは、不必要に冗長で醜いことがよくあります)、しかし、あなたは合理的に同意しないかもしれません-それはやや主観的な呼び出しです.
この議論に基づいて、PHP 開発者は言語で警告を保持しましたよね?
ええと、正確ではありません。
上記にリンクされている PHP バグ レポート 53081 では、static::foo()
構造体の追加により抽象静的メソッドが合理的かつ有用になったため、警告を削除するよう求められました。Rasmus Lerdorf (PHP の作成者) は、要求が偽物であるとラベル付けすることから始め、警告を正当化しようとする長い一連の悪い推論をたどります。そして最後に、次の交換が行われます。
ジョルジオ
知ってるけど:
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();
ラスムス
そうです、それはまさにそれがどのように機能するべきかです。
ジョルジオ
しかし、それは許可されていません:(
ラスムス
何が許可されていませんか?
abstract class cA {
static function A(){static::B();}
abstract static function B();
}
class cB extends cA {
static function B(){echo "ok";}
}
cB::A();
これはうまくいきます。明らかに self::B() を呼び出すことはできませんが、 static::B() は問題ありません。
彼の例のコードが「正常に動作する」という Rasmus の主張は誤りです。ご存じのとおり、厳格モードの警告がスローされます。彼は厳密モードをオンにせずにテストしていたと思います。とにかく、混乱した Rasmus は、リクエストを「偽物」として誤って閉じたままにしました。
そして、それが警告がまだ言語にある理由です。これは完全に満足のいく説明ではないかもしれません - あなたはおそらく警告の合理的な正当化を期待してここに来ました. 残念ながら、現実の世界では、合理的な意思決定ではなく、ありふれた過ちや不適切な推論から選択が生まれることがあります。これは単にそれらの時間の 1 つです。
幸いなことに、評価の高い Nikita Popov が、 PHP RFC: Reclassify E_STRICT noticesの一部として、PHP 7 の言語から警告を削除しました。最終的には正気を保てるようになり、PHP 7 がリリースされれabstract static
ば、このばかげた警告を受けることなく、誰もが問題なく使用できるようになります。