イントロダクション
ファサードはアプリケーションのIoCコンテナに用意したクラスに「静的」なインターフェイスを提供してくれます。Laravelは多くのファサードを使用していますが、多分皆さんはご存じないまま使用されていることでしょう!Laravelの「ファサード(facade)」は、IoCコンテナー下で動作しているクラスに対し、"static proxies"として動作しています。これにより伝統的な静的メソッドよりも、簡潔で、テストの行いやすさと柔軟性を保ちながらも、記述的な書き方が行えます。
自分のアプリケーションやパッケージでも時々ファサードを作成したくなると思います。ですからコンセプトと、開発方法、クラスの使い方を説明していきます。
注目:ファサードを学び始める前に、LaravelのIocコンテナに親しんでおくことを強くおすすめします。
解説
Laravelアプリケーションに関する文脈では、ファサードはコンテナを通じてオブジェクトにアクセス方法を提供するクラスのことです。Facade
クラス中のメカニズムでこれを行なっています。Laravelのファサードと皆さんが作成したカスタムファサードは、Facade
クラスを拡張します。
ファサードクラスで実装する必要があるのはgetFacadeAccessor
だけです。getFacadeAccessor
メソッドの役目はコンテナを通じたインスタンスの解決に何を使用するかを定義することです。Facade
基本クラスは__callStatic()
マジックメソッドを使用し、あなたのファサードからの呼び出しをインスタンス化を解決したオブジェクトへと届けます。
Cache::get
のようにファサードの呼び出しが行われると、LaravelはIoCコンテナでCacheマネージャーを解決し、そのクラスのget
メソッドを呼び出します。技術的な言い方をすれば、Laravelのファサードは、サービスローケーターとしてのLaravelのIoCコンテナを使用した、使いやすい記法のことです。
実際の使用
下の例では、Laravelのキャッシュシステムを呼び出しています。これを読むと、一見Cache
クラスのstaticなget
メソッドが呼び出されていのだと考えてしまうことでしょう。
$value = Cache::get('key');
ところが、Illuminate\Support\Facades\Cache
クラスを見てもらえば、staticのget
メソッドは存在していないことが分かります。
class Cache extends Facade {
/**
* コンポーネントの登録名を取得する
*
* @return string
*/
protected static function getFacadeAccessor() { return 'cache'; }
}
Cacheクラスは基本のFacade
クラスを拡張し、getFacadeAccessor()
メソッドを定義しています。思い出してください。このメソッドの仕事はIoCで結合した名前をリターンすることでした。
ユーザーがCache
ファサードのどのstaticメソッドを利用しようと、LaravelはIoCコンテナからcache
に結び付けられたインスタンスを解決し、要求されたメソッドを(この場合はget
です)そのオブジェクトに対し実行します。
ですから、Cache::get
の呼び出しは以下のように書き直すこともできます。
$value = $app->make('cache')->get('key');
ファサードの作成
ファサードを作成するとアプリケーションやパッケージをシンプルにすることができます。必要なのは3つだけです。
- IoCでのバインディング
- ファサードクラス
- ファサードエイリアスの設定
例を見てください。PaymentGateway\Payment
クラスを定義しています。
namespace PaymentGateway;
class Payment {
public function process()
{
//
}
}
このクラスはapp/models
ディレクトリーの中に設置されることでしょう。もしくは、Composerがオートロードできるディレクトリーの中に設置します。
IoCコンテナでこのクラスのインスタンス化を解決することが必要です。では、バインディングを追加しましょう。
App::bind('payment', function()
{
return new \PaymentGateway\Payment;
});
このバインディングコードを設置する良い場所は、新しいPaymentServiceProvider
という名前のサービスプロバイダーを作成し、register
メソッドにこのコードを追加します。それから、app/config/app.php
設定ファイルでこのサービスプロバイダーをLaravelがロードするように設定します。
次に、ファサードクラスを作成しましょう。
use Illuminate\Support\Facades\Facade;
class Payment extends Facade {
protected static function getFacadeAccessor() { return 'payment'; }
}
最後に、お望みならば、app/config/app.php
設定ファイルのaliases
配列にファサードクラスのエイリアスを追加することもできます。これで、Payment
クラスのインスタンス上でprocess
メソッドを呼び出すことができます。
Payment::process();
オートローディングエイリアスの注意点
PHPが未定義のタイプヒントをオートロードしないため、aliases
配列中のクラスが、使用できない場合があります。もし、\ServiceWrapper\ApiTimeoutException
をApiTimeoutException
というエイリアス名で定義し、\ServiceWrapper
外の名前空間でcatch(ApiTimeoutException $e)
しても、投げられたその例外は捕捉されません。似たような問題は、エイリアスされたクラスへのタイプヒントを持つモデルでも、見かけられます。解決するには、そのようなエイリアスの参照に先立ち、それぞれのファイルの先頭で、必要なタイプヒントをuse
で指定しておく方法しかありません。
ファサードのモック
ファサードがどうしてこのように動作するのかという理由の重要な一面が、ユニットテストです。実際、ファサードが存在している一番大きな理由がテストの行いやすさです。詳細はドキュメントのファサードのモックの章をご覧ください。
ファサードクラス一覧
以下は全ファサードと、実際のクラスの一覧です。これは特定のファサードを元にし、APIドキュメントを素早く探したい場合に便利な道具になります。IoC結合キーも含んでいますので、応用して下さい。