PHPのオブジェクトから、自身のアクセス不能メソッドを静的コンテキストで呼び出せない件という記事がありますが、簡単に言うとインスタンス中から自分自身の__callStaticを呼び出せないというものです。
class A{
public function __construct(){
static::hoge(); // call
self::hoge(); // call
A::hoge(); // call
}
public static function __callStatic($a, $b){ echo 'callStatic'; }
public function __call($a, $b){ echo 'call'; }
}
new A();
いずれも一見__callStatic
が呼び出されそうに見えますが、実際は__callが3回呼ばれます。
さて何故このような実装になっているかというと、いわゆる歴史的な理由というやつだと思われます。
まず2009年のPHP5.3.0で__callStatic
が実装されました。
この時点で既に上記プログラムの出力はcallcallcallでした。
何故このような実装になったのかははっきりとはわかりませんが、おそらく単にcallを先にチェックしてるからというだけな気がしてなりません。
ちなみに実装者のSara GolemonはPHP4の時代から2018年の今まで活躍してるすごい人です。
その後PHP5.3.2が出たあたりでバグチケットが提出されました。
ここで__call
が呼ばれるのはおかしいよね、__callStatic
だよね、という内容です。
これはおかしいから修正しよう、ということになって修正がマージされ、PHP5.3.3としてリリースされました。
さてPHP5.3.3のリリース後、新たなバグチケットが出されました。
前は__callが呼ばれてたのにPHP5.3.3で__callStaticが呼ばれるようになったんだがどういうことだ、という主張です。
さきほどのバグチケットとは全く反対の内容ですね。
ということで話はPHP-DEVメーリングリストに持ち込まれ、これは元に戻すべきだということになって5.3.4でRevertされました。
実際に動作を見てみると、PHP5.3.3のみcallStaticになります。
ここで仕様が完全に確定され、この動作が正と判断されることになりました。
その後も同じようなバグチケットが幾度となく提出されていますが全て却下されています。
まあ確かに直感的な動作とは言いがたいですから、何度もチケットが出される理由もわからないでもないですね。
まとめ
・PHP5.3.0で__callStaticが実装された。動作は現在と同じ。
・PHP5.3.3でself::やstatic::が__callStaticを呼び出すように変更された。
・PHP5.3.4でRevertされて元に戻った。
感想
そもそもstaticなメソッドなので、self::やstatic::からは参照できなくても仕方ない気はしますね。
ただA::hoge()
で呼び出せないのはとても良くないのではなかろうか。
その他
親クラスにprivateメソッドがあると動作が変わります。なんでだよ。
class A{
public static function __callStatic($a, $b){ echo 'callStatic'; }
public function __call($a, $b){ echo 'call'; }
private function hoge(){}
}
class B extends A{
public function __construct(){
static::hoge(); // callStatic
self::hoge(); // callStatic
A::hoge(); // callStatic
static::fuga(); // call
self::fuga(); // call
A::fuga(); // call
}
}
new B();
親クラスにprivateのhoge()
が存在すると、子クラスからhoge()
を使うと全てのバージョンでcallStaticになります。
このバグ2011年に提出されているのですが、何故か完全にスルーされてます。
つまり、どうしても__callStaticを呼びたければprivateメソッドを置いておけばいいということだね(錯乱)