【PHP】無名クラスを継承する方法

  • 2023年11月21日
  • 2023年11月21日
  • PHP

 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 はあるクラスを別名でも扱えるようにするという関数です。

PHP: class_alias – Manual

 このヒントを元にした 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が継承元を追えず普通でない書き方でもありますので積極的に使いたくないですが、このようにして無名クラスを継承できます。

>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG