PHPのRFCで次の提案がされています。無名クラスに final を導入しようというものです。この提案では final を使えるようにするか必ず final にするかのどちらかにしたい、ということが伝えられています。
PHP: rfc:final_anonymous_classes
RFCの見出しを見た時、自分は提案の内容そのものよりも今は無名クラスが継承できる、という方が気になりました。なぜなら素直に継承させようとすると次のように文法エラーになるためです。
<?php $anonymous = new class { public function echoMsg(): void { echo 'Hello World' . PHP_EOL; } }; class ExtendAnonymous extends $anonymous // ←ここに無名クラスのインスタンスの変数はおけない { } // Parse error: syntax error, unexpected variable "$anonymous" in /xxx/tmp.php on line 9
Online PHP editor | output for TUgi6#上記コードの実行デモ
継承を書くときは通常class 新しいクラスの名前 extends 継承したいクラスの名前
となります。これを無名クラスでやろうにも名前が無いのでなんともなりません。無名クラスを指し示せるのはそのインスタンスですが、変数をそのままいれても上記の様に文法エラーとなります。一見、継承はできないように見えます。
冒頭のRFCには次のようにあります。
However, I understand that this might be a little bit too restrictive for something that may have some valid usecases, even if extending anonymous classes currently requires some hack-ish workarounds with class_alias.
しかし、たとえ匿名クラスを拡張するためにclass_aliasを使ったハック的な回避策が必要だとしても、いくつかの有効なユースケースがあるかもしれないものに対して、これは少し制限的すぎるかもしれないと私は理解している。
無名クラスは常に final にしたいけれども、それが破壊的変更なのは理解しているのでオプショナルになる提案もします、とかそんな感じの文脈での一文です。これは class_alias を使えば継承できるよ、というヒントでもあります。class_alias はあるクラスを別名でも扱えるようにするという関数です。
このヒントを元にした class_alias を使った無名クラスを継承するコードが次です。
<?php $anonymous = new class { public function echoMsg(): void { echo 'Hello World' . PHP_EOL; } }; // get_class($anonymous) で無名クラスのPHP内での名前を得る // class_alias で IHaveName というクラス名のエイリアスを作る class_alias(get_class($anonymous), 'IHaveName'); // 無名クラスのエイリアスである IHaveName を継承させる class ExtendAnonymous extends IHaveName { } // 動く $instance = new ExtendAnonymous(); $instance->echoMsg(); // Hello World var_dump($instance); // object(ExtendAnonymous)#2 (0) { // } var_dump(get_class($instance)); // string(15) "ExtendAnonymous" var_dump($instance instanceof $anonymous); // bool(true)
Online PHP editor | output for ZoV4D#上記コードの実行デモ
こんな感じで class_alias を使って無名クラスを継承したクラスが作れます。しっかり無名クラス側のメソッドが呼べますし、instanceof も通ります。IDEが継承元を追えず普通でない書き方でもありますので積極的に使いたくないですが、このようにして無名クラスを継承できます。