時折、再利用する気もないその場限りのクラスオブジェクトが欲しくなる時があります。例えば、インタフェースを満たしたクラスオブジェクトが引数として要求されているが既存のそのインタフェースを満たしたクラスを使いたくない時です。そういった時ファイルを分けてクラスを新たに記述するのも手ですが、コード量がさほどでもなく、再利用する気もなく、拡張する予定もない時は使いどころのファイル内に記述したくなります。この時、1 ファイル内に 2 クラス書くこともできますが、これは PSR-4 に反しており一見外部から呼べそうながらも呼べない時があるクラスができることになり、事故の元となります。
/** app/TmpA.php */
// クラス定義ファイル。 TmpB が呼べない時のあるクラスです
namespace App;
class TmpA {
}
class TmpB {
}
/** script_fail.php */
// composer のオートローダ(PSR-4)でクラスを探します
require __DIR__.'/vendor/autoload.php';
new \App\TmpB(); // Uncaught Error: Class 'App\TmpB' not found でエラーになります。
/** script_success.php */
// composer のオートローダ(PSR-4)でクラスを探します
require __DIR__.'/vendor/autoload.php';
new \App\TmpA();
new \App\TmpB(); // TmpA でロードされたファイル中に \App\TmpB が定義されているのでエラーになりません。
1 ファイル中に複数クラスを書きながらも PSR-4 に反しない仕組みとして無名クラスがあります。
PHP: 無名クラス – Manual
無名クラスは例えば次の様に使えます。
<?php
class Hoge
{
}
/**
* インタフェースを満たせ、継承もできます
* コンストラクタに引数を渡すこともできます。
*/
$instance = new class(['a', 'b', 'c']) extends Hoge implements JsonSerializable {
/** @var array プロパティを持てます */
protected $arr;
/**
* コンストラクタを持てます
* @param array $arr
*/
public function __construct(array $arr)
{
$this->arr = $arr;
}
/**
* JsonSerializable を満たすためのメソッドです
* @return array
*/
public function jsonSerialize()
{
return $this->arr;
}
};
echo json_encode($instance);// ["a","b","c"]
滅多に使わない機能ですが、その場で書き捨てるスクリプトやごく短く限られた範囲におけるDTO(DataTransferObject)などとして使うと案外便利です。