Laravelのファサードとはなにか
ずっと使っているけど十分に理解できなかったので調べた。
ファサードとはなにか
結論から言うと、ファサードは、対応したサービスのインスタンスのメソッドを、静的にコールできる仕組み、のようだ。
GoFのデザインパターンのFacadeパターンとはちょっと違う。あれは複数の複雑な機能に対する一つのアクセス方法を提供するものだったと思うので。こっちはもっとシンプル。多少の例外はあるが、基本的にはサービスに委譲するだけだ。
Illuminate\Support\Facades\Request
ファサード(以下Requestファサード)を例に挙げる。このファサードは'request'
エイリアスのサービスと対応していて、その実体はIlluminate\Http\Request
のインスタンスである。
コントローラアクションで、Illuminate\Http\Request
をDIして持って来た$request
のたとえば$request->all()
と、ファサードのRequest::all()
は同等になる。
<?php namespace App\Http\Controllers; use Illuminate\Http\Request as HttpRequest; use Illuminate\Support\Facades\Request; class TestController extends Controller { public function index(HttpRequest $request) { dd($request->all(), Request::all()); # 等しい } }
ファサードはどう実装されているか
まずファサードはクラスである。Illuminate\Support\Facades
名前空間以下にあるクラスで、Illuminate\Support\Facades\Facade
抽象クラスを継承している。
ファサードクラス内にはgetFacadeAccessor()
というメソッドが共通して存在していて、これが肝になっている。単純にこの戻り値によって対応するサービスが決まっている。
大抵文字列で、サービスのエイリアスが返されているが、Schemaファサードに関してはオブジェクトが直接返されていたりする。
オブジェクトの場合はそのまま使うだけだが、サービスのエイリアス等の場合は、必要に応じてresolve()
相当の解決が行われている。
つまりRequestファサードで静的にメソッドを呼び出すのと、resolve('request')
されたオブジェクトのメソッドを呼び出すのも同じことになる。
<?php namespace App\Http\Controllers; use Illuminate\Support\Facades\Request; class TestController extends Controller { public function index() { dd(resolve('request')->all(), Request::all()); # 等しい } }
関連1: クラス名のエイリアス
ファサードに関連する紛らわしい個所が2つある。1つはクラス名のエイリアスで、ファサードとは直接関係ないがほぼファサードに関連して使われている。
これはuse Request
がuse Illuminate\Support\Facades\Request
と同等になるあたりの話だ。
通常エイリアスを使うことはほぼ使わないと思うが、一部の素のPHPスクリプト上では、use
せず、エイリアスが直接使われていることがあるかもしれない。
php artisan ui vue --auth
などとして認証機能を有効にした場合、routes/web.php
にAuth::routes()
が追加されるが、このときファイル上部ではuse
Illuminate\Support\Facades\Auth
とはされていないはずだ。
これはエイリアスのおかげで動作している。
エイリアスは単純に、spl_autoload_register()
を使って、動的にclass_alias()
されることで設定されている。
設定されているエイリアスに関しては、Illuminate\Foundation\AliasLoader::getInstance()->getAliases()
をtinker等から実行すれば確認できる。
これらのほとんどはconfig/app.php
のaliases
で設定されるものだが、一部Composerでインストールされたパッケージから設定されるものがある。composer.lock
(じっさいにはinstalled.json
から読まれているが)のパッケージ設定にextra.laravel.aliasesがある場合、config/app.php
のaliases
のものに追加でエイリアスが作られる。
デフォルトではLaravel 7のエラー表示パッケージであるIgnitionから、Flareクラスのエイリアスが設定されているはずだ。
// ... { "name": "facade/ignition", // ... "extra": { "laravel": { "aliases": { "Flare": "Facade\\Ignition\\Facades\\Flare" } } }, }, // ...
関連2: Arr, Str
もう1つはIlluminate\Support
以下の、Arr, Strクラスだ。これらのクラスはファサードではないが、静的メソッドの使用がメインで、かつエイリアスも設定されているため、場合によってはファサードと区別がしづらいかもしれない。
とはいえ区別する必要もあまりない。クラスのソースコードを見れば、一目で裏にサービスインスタンスのない静的メソッドだけのクラスとわかる。