17
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

自分自身から__callStaticを呼び出したい

Last updated at Posted at 2018-06-27

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メソッドを置いておけばいいということだね(錯乱)

17
10
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?