Laravelにはファサード(Facade)という便利機能がある。RequestやRedirect、Viewなどデフォルトでかなり多くのファサードが登録されています。
ここでは、そもそもファサードとは何なのか?ファサードを使うメリットは何なのか?に加え、実際にファサードを自分で作成する方法について解説します。
ファサード(Facade)とは?
ファサードとは簡潔にいうと、クラスをインスタンス化しなくても、静的(static)メソッドのように使える機能のことです。
ポイントは「インスタンス化不要」という点です。インスタンス化する手間を省けるため、コードがシンプルになり可読性が向上します。
特に、クラスの中で他のクラスを使う場合など、その処理を実行するのに必要なクラスのメソッドを使えるようにしてくれます。
これを、依存解決と言います。実際にはファサードではなくサービスの機能なのですが、ファサードとして登録するためにはサービスとして登録する必要があるため、この機能も含まれます。
ファサードや依存解決という聴き慣れない単語のせいで何かすごく専門的で難しいことのように感じてしまいますが、処理をシンプルに記述できるようになるというだけのものです。RequestやRedirectなど頻繁に呼び出すクラスがファサードとして登録されています。
ちなみに、Facadeとは入り口といった意味です。家の中のメソッドにアクセスして呼び出さなくても、入り口にアクセスすれば、そのメソッドを呼び出せるというニュアンスになります。
ファサードはデフォルトで用意されているもの以外にも、自分で作成することもできます。
静的(static/スタティック)メソッドとは?
静的メソッドはクラスに定義したメソッドで、インスタンスによらず常に同じ処理を実行します。スタティックメソッドやクラスメソッドとも呼びます。
静的メソッドの呼び出しは、 クラス名::メソッド名() として呼び出します。
例えば、クラス名TestClassのtest_methodを呼び出す場合で見ると、インスタンスメソッドとの呼び出し方の違いは以下のようになります。
TestClass::test_method();
//インスタンスを生成
$obj = new TestClass;
$obj->test_method()
静的メソッドはインスタンス化する必要がないので、記述がシンプルになります。それぞれの詳細については以下をご参照ください。
(参考)【PHP】静的(スタティック)メソッドと動的(インスタンス)メソッドの違いとは何か?実例でわかりやすく解説。
ファサードのメリットとデメリット
メリット
先述しましたが、メリットは大きく2つです。
- インスタンス化不要(記述の省略)
- 依存解決
ファサードとして登録すると、記述がシンプルになります。クラスのメソッドを使いたい場合に、インスタンス化するコードを省けます。
また、そのクラスのメソッドを使うときに、必要になる他のクラスのインスタンスも自動で生成してくれます。複雑な処理に慣ればなるほど、とてもありがたみが増します。
一度しか使わない処理であれば、わざわざファサード化する必要はありませんが、RequestやRedirect、Route、View、、、、などのように頻繁に使うメソッドは、ファサード化してあれば記述がとてもシンプルになります。
デメリット
ファサードのデメリットは大きく2つです。
- 作成の手間がかかる(複数のファイルを編集する必要がある)
- 処理の流が見えにくい
ファサードを作成する場合は、複数のファイルを編集する必要があります。このため、プロジェクト全体の中で数回しか使わない処理であれば、わざわざファサード化するのは手間です。
また、複数のファイルを経由したり、他のクラスも関連していたりする場合があるため、処理の流も見えにくくなります。
入り口(ファサード)だけ使って、家の中には入らないといった感じです。複雑な家の中ほどごちゃごちゃです。
ファサードの作成手順概要
ファサードを使うための手順は大きく4つです。
- クラスの作成
- サービスプロバイダに登録
- ファサードとして登録
- エイリアスを登録
ファサードを使うためには、対象のクラスをサービスに登録する必要があります。そして、基本的にはファサードのエイリアスを作成し、そのエイリアスを使って処理を記述します。
サービスやサービスプロバイダとは?
サービスとは、ここではLaravel専門の用語になります。Laravelでクラスに好きな名前をつけて、どこからでも呼び出せるようになります。また、依存解決もしてくれます。
依存解決とは、あるクラスのメソッドを実行するために必要なクラスのメソッドも使えるようにしてくれる便利機能のことです。
サービスは、サービスコンテナの中に登録されます。コンテナというとDockerを連想する人もいるかもしれませんがここでは関係ありません。サービスを入れておく場所程度に考えておけば問題ありません。
そして、サービスコンテナにサービスを登録するためには、サービスプロバイダーを使います。名前の通りサービスを提供するものです。サービスプロバイダーとして登録されている(or 登録した)ファイルに、処理を記述すればサービスの登録は完了です。
サービスプロバイダーは AppServiceProvider.php のようにデフォルトで登録されているものもあれば、自分で登録することもできます。
エイリアスとは?
ファサードを登録した後に、エイリアスとして登録する処理をします。
エイリアスはファサードとは別物ですが、ファサードをエイリアスとして登録することで、呼び出しの記述をとても簡単にすることができます。
エイリアスは登録したクラスをグローバル名前空間として使えるようにしてくれる機能です。
例えば、 Laravelでよく使うRequestというファサードは、エイリアスとして登録されているため、
Request::メソッド
のみの記述で簡単に使うことができます。しかし、エイリアス登録してない場合は、名前空間を指定する必要があるので、
Illuminate\Support\Facades\Request::メソッド名
としなければいけません。毎回この長いのを書くのは大変です。このためファサードを作成したら、基本的にはエイリアスとして登録し、すぐに使えるようにします。
ファサードの作成実例
実際にファサードを作ってみます。
クラスの作成
まずは登録したいクラスを作成します。クラスはどこに作成してもいいのですが、サービスに登録することがわかりやすいように、 App > Services というディレクトリを作成して、その中に作成すると管理がしやすいです。
ファイル名とクラス名も好きなもので大丈夫です。
ただし1つだけとても重要な点があります。それは、ファイルパスと、クラス名を合わせることです。これをしないと、コンパイルエラーが発生します。(composer dump-autoloadの仕様です)
以下のように、app > Services > Hello.php を作成した場合、
名前空間は、ディレクトリに合わせて App\Services とし、クラス名はファイル名と合わせて Hello.phpとします。
<?php
namespace App\Services
class Hello
{
public static function greeting(){
echo "Hello! App\Services\Hello";
}
}
※冒頭の <?php は必須です。これがないとphpとしてコンパイルできません。(.phpファイルであっても)
サービスプロバイダに登録
クラスの作成ができたら、サービスプロバイダに登録します。何やら難しく聞こえますが、やることはとても簡単です。
デフォルトでサービスプロバイダとして登録されている、app > Providers > AppServiceProvider.phpファイルを使います。(※好きなファイルを自分で作ることもできます。)
サービスプロバイダは、クラス ServiceProvider を拡張したクラスで、その中に、registerという関数があります。デフォルトでは処理は何も記載されていません。
登録方法には決まりがあります。 Laravelにデフォルトで用意されている、appヘルパのbind(もしくは singleton)メソッドを使って、クラス名や処理に、好きなサービス名をつけて登録します。
public function register()
{
app()->bind('サービス名', 'クラス名');
}
public function register()
{
app()->bind('サービス名', function () {
処理;
});
}
ここでは、サービス名を ReturnHello として、先ほどのクラスを登録します。ファイルの全貌は以下のようになります。
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
app()->bind('ReturnHello', 'App\Services\Hello');
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
//
}
}
以上で、サービスの登録は完了です。
この時点で、プロジェクトの好きな場所からこの登録したサービスを呼び出すことができます。呼び出しは、 app()->make(‘サービス名’) としてインスタンスを生成し、インスタンスメソッドを呼び出します。
$obj = app()->make('ReturnHello');
$obj->greeting();
例えば、ビューファイルの中に以下のように記述してブラウザをリロードすれば、指定した処理が実行されます。
<div>
<?php
$obj = app()->make('ReturnHello');
$obj->greeting();
?>
</div>
参考
なお、bindメソッドで登録した場合は、サービスを呼び出すときに都度新しいインスタンスを生成します。
一方、singleton(シングルトン)メソッドで登録した場合は、初回にインスタンスを生成し、あとはその生成済みのインスタンスを呼び出します。
singletonを使ったファサードの登録例は以下をご参照ください。
(参考)Laravel-breadcrumbsを使って簡単にパンくずの構造化マークアップを実装する方法(全てのページに適用する手順)
app()の部分は、$this->appにしても同じ処理になります。違いについては以下をご参照ください。
(参考)【Laravel】「$this->app->メソッド」と「app()->メソッド」の違い(appカッコ メソッドとは?)
ファサードとして登録
サービスとして登録した時点でどこからでも呼び出せるようになりましたが、インスタンスを生成しなければ関数が使えません。
そこでファサードとして登録して、インスタンス生成の記述を省けるようにします。
ファサード登録用のファイルを作成
ファサードとして登録するために、専用のファイルを作成します。
ファイルパスやファイル名に特に指定はないのですが、Helloクラスのファサードであることがわかりやすいように、app > Facades > HelloFacade.php とします。(名前空間が違うので、先ほどと同じくHello.phpとしても機能します)
ファサードとして登録
ファサードとして登録するには決まった記述方法があります。記述自体はとても簡単です。
実際の記述例は以下のようになります。
<?php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class HelloFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'ReturnHello'; // サービス名
}
}
コピペして、(1)名前空間、(2)クラス名、(3)サービス名 の3点を変更すればOKです。
以上でファサードの登録が完了です。これで、インスタンスを生成せずともどこからでも呼び出すことができます。
呼び出しは、 ファサードの完全なクラス名::メソッド() を記述します。上記例では、App\Facades\HelloFacade::greeting() です。
ポイントは以下の2つです。
- インスタンスを生成する記述が不要(Laravelが自動でやってくれる)
- クラスメソッドとして呼び出す(大元のメソッドはインスタンスメソッドとして登録している)
Laravelが色々と自動で処理してくれていることがわかります。
実際に、ビューに記述してブラウザで呼び出してみます。
<div>
<?php
\App\Facades\HelloFacade::greeting();
?>
</div>
インスタンス化せずとも、処理を呼び出すことができました。
ビューの中の記述で、ファサードを呼び出すときに、クラス名の冒頭に「\」バックスラッシュを記載していますが、これは、グローバルな名前空間であることを明示した記述になります。 詳細については以下をご参照ください。
(参考)【PHP】クラス名や名前空間の先頭・冒頭につけるバックスラッシュ \の意味は何か?
エイリアスの登録
ファサードの登録は完了し、\App\Facades\HelloFacade で呼び出せるようになりましたが、クラス名が長いので、これを「Hello」のみで呼び出せるようにします。
ルートディレクトリ直下の config > app.php ファイルを開きます。この中の下の方に、aliasesと書かれた場所があります。
ここに、よく使う、App, Route, Request, Viewなどのファサードがエイリアスとして登録されています。
'aliases' => [
'App' => Illuminate\Support\Facades\App::class,
'Arr' => Illuminate\Support\Arr::class,
'Artisan' => Illuminate\Support\Facades\Artisan::class,
//以下省略
],
登録方法は、 ‘エイリアス名’ => ‘完全なクラス名’ です。配列の中の一番下に以下のように追記します。
'aliases' => [
'App' => Illuminate\Support\Facades\App::class,
//以下省略
'Hello' => App\Facades\HelloFacade::class,
],
以上でエイリアスの登録は完了です。とても簡単ですね。
実際に、ビューに記述してブラウザで呼び出してみます。
<div>
<?php
\Hello::greeting();
?>
</div>
正しく処理が実行されていることが確認できます。
以上で、ファサードの登録およびエイリアスの設定は完了です。
まとめ
ファサードとエイリアスを登録することで、コードをどこからでも簡単に記述できるようになることがわかりました。
記述がどのように省略されていくかをまとめると以下のようになります。
登録状態 | クラスの呼び出し | 例 |
---|---|---|
サービス | app()->make(‘サービス名’) | app()->make(‘Hello’) |
ファサード | 名前空間\クラス名 | \App\Facades\HelloFacade |
エイリアス | エイリアス名 | \Hello |
使い回すクラスの処理で、複数のクラスのメソッドをまたぐ場合などに、効果を発揮するので、ぜひ、色々と試してみてください。