Laravelを使っていると頻繁に現れるのがファサードです。Laravelの特徴とも言われています。このファサードを実際に作成しながら、理解を深めたいと思います。
なお、この記事を読み進めるにあたり、事前に以下の記事を読んでおくことを、おすすめします。
ファサードとは?
ファサードとは一体何でしょうか?
公式ドキュメントには以下の様に書かれています。
- ファサードはサービスコンテナで利用可能なクラスへの “static” インターフェースを提供します。
- ファサードはサービスコンテナからオブジェクトへのアクセスを提供するクラスです。
# 実際の使用例
ファサードは以下の様に使用します。Routeファサードを使用する例です。
Route::get('/', 'WelcomeController@index');
一見すると、Routeクラスの static メソッドである get() を実行しているように見えますが、実は、Illuminate\Routing\Router のインスタンスの get() が実行されています。
# ファサードクラスの中身
Routeファサードの中身を見てみます。get() メソッドが無いことがわかります。
<?php namespace Illuminate\Support\Facades; class Route extends Facade { // ① /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'router'; // ② } }
① Routeクラスは、Facadeクラスを拡張しています。
② getFacadeAccessor() メソッドを実装し、ここでサービスコンテナにバインドしてあるキー名を返しています。
親クラスである Facadeは、static メソッドがコールされると、getFacadeAccessor() から返されるキー名でサービスコンテナからインスタンスを取得します。そして、そのインスタンスのメソッド(この場合は get です)を実行します。
先ほどの Routeファサードの使用例は、以下のように書き換えることができます。
$this->app->make('router')->get('/', 'WelcomeController@index');
# 何故ファサードを使うのか?
ファサードの正体が分かったところで、いったい何故このような仕組みが必要なのか疑問が湧いてきました。どの様なメリットがあるのでしょう?答えは次の3つかと思います。
- ファサードは依存性注入の1つの方法です。依存性注入を使うと柔軟性、保守性が上がります。詳細は「依存性の注入とは」をご覧ください。
- サービスコンテナを介してインスタンスにアクセスする為、オブジェクトをシングルトンとして登録できます。毎回クラスを new するのに比べて、メモリー効率、パフォーマンス効率が上がります。
- サービスコンテナを介してインスタンスにアクセスする為、テストを記述する時に、モックに入替えることが出来ます。
ファーサードの作成
では、実際にファサードを作成してみます。以下の手順となります。
- クラスを作成
- サービスプロバイダーを作成
- サービスプロバイダーの設定
- ファサードクラスを作成
- ファサードを使ってみる
- ファサードエリアスの設定
# クラスを作成
ファサードの対象となる Paymentクラスを作成します。
<?php // app/Services/Payment.php namespace App\Services; class Payment { public function pay($money) { // ここで支払い処理をします。 return "$money 円の支払いが完了しました。"; } }
# サービスプロバイダーを作成
artisan コマンドでサービスプロバイダーを作成します。
php artisan make:provider PaymentServiceProvider
<?php // app/Providers/PaymentServiceProvider.php namespace App\Providers; use Illuminate\Support\ServiceProvider; class PaymentServiceProvider extends ServiceProvider { public function boot() { // } public function register() { $this->app->bind( // ① 'payemnt', 'App\Services\Payment' ); } }
① サービスコンテナに ‘payment’ キーで、Paymentクラスをバインドします。
# サービスプロバイダーの設定追加
config/app.php に PaymentServiceProvider を追加します。
<?php // config/app.php // … return [ 'providers' => [ // ... /* * Application Service Providers... */ 'App\Providers\AppServiceProvider', 'App\Providers\BusServiceProvider', 'App\Providers\ConfigServiceProvider', 'App\Providers\EventServiceProvider', 'App\Providers\RouteServiceProvider', 'App\Providers\PaymentServiceProvider', // 追加 // ... ], // ... ];
# ファサードクラスを作成
Paymentファサードクラスを作成します。こちらは手動で作成します。
ファサードクラスは app/Facades ディレクトリを作成し、そこに格納することにしました。
<?php // app/Facades/Payment.php namespace App\Facades; use Illuminate\Support\Facades\Facade; class Payment extends Facade { protected static function getFacadeAccessor() { return 'payment'; // ① } }
① 先ほど、PaymentServiceProviderの register()メソッドでサービスコンテナに Paymentをバインドした時のキー名(’payment’)を返します。
# ファサードを使ってみる
app/Http/route.php 内で Paymentファサードを使ってみます。
// app/Http/routes.php Route::get('pay/{money}', function($money){ return \App\Facades\Payment::pay($money); // ① })->where('money', '[0-9]+');
① ルートのクロージャー内で Paymentファサードを使います。
名前空間を指定してPaymentファサードクラスを使用します。
http://localhost:8000/pay/10000 へアクセスするとファサードが上手く機能して、以下のように表示されます。
10000 円の支払いが完了しました。
# エリアスの設定
config/app.php に Paymentファサードのエリアスを追加します。
<?php // config/app.php // … return [ 'aliases' => [ // ... 'Payment' => App\Facades\Payment::class, ], // ... ];
エリアスはグローバル名前空間に設定されます。
エリアスを使う様に app/Http/routes.php を修正します。
// app/Http/routes.php get('pay/{money}', function($money){ // return \App\Facades\Payment::pay($money); return \Payment::pay($money); // グローバル名前空間にあるエリアスを使用 }) ->where('money', '[0-9]+');
http://localhost:8000/pay/10000 へアクセスして動作確認をします。
10000 円の支払いが完了しました。
まとめ
ファサードについて理解することができました。
- ファサードの使用方法
- ファサードの仕組み、実態
- ファサードの作成方法
- ファサードとサービスコンテナ、サービスプロバイダーとの関連
- エリアスの設定
「ファサードとは」への1件のフィードバック