Laravel公式を読み解く 10. Laravel 5.5 ファサード
https://readouble.com/laravel/5.5/ja/facades.html
・ファサードとは
簡単に独自クラスのメソッドを呼び出せるようにした機能。
なるべくロジックの記述を奥にしまいこんで、簡潔にクラスのメソッドを呼び出すようにする。
https://laraweb.net/practice/2065/
Facadeは(staticクラスっぽいけど)staticクラスではない
FacadeはgetFacadeRoot()を使って、コンテナから取得したインスタンスを返却している
Facade::__callStatic()を使って、返却されたインスタンスのメソッドを呼び出している
https://public-constructor.com/laravel-what-is-facade/
・ファサードの解読!
①Route::get('/', 'WelcomeController@index');
⇒これは、Routeクラスのstaticメソッドget()を呼び出しているのではない。
②config/app.php
'Route' => Illuminate\Support\Facades\Route::class
エイリアス登録欄に、↑が登録されている。「Routeと呼ばれたらIlluminate\Support\FacadesのRouteクラスのことを示す」と。
③/vendor/laravel/framework/src/Illuminate/Support/Facades/Route.php
namespace Illuminate\Support\Facades;
protected static function getFacadeAccessor()
{
return 'router';
}
Facadeクラスを拡張したRouteクラスがある。Routeクラス含め、Facadeクラスを拡張したクラスには、getFacadeAccessor()メソッドしかない。
これは、サービスコンテナからインスタンスを生成するためのキーを返すメソッド。
(サービスプロバイダに登録された、 インスタンス生成のあだ名を返す。)
④注意!!③の親クラスのFacadeクラスについて!
/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php
protected static function getFacadeAccessor()
{
throw new RuntimeException('Facade does not implement getFacadeAccessor method.'); //→getFacadeAccessorメソッド はありませんよ???
}
// 省略
public static function __callStatic($method, $args)
{
$instance = static::getFacadeRoot();
if (! $instance) {
throw new RuntimeException('A facade root has not been set.');
}
return $instance->$method(...$args);
}
というマジックメソッドがある。
⇒呼ばれた、Facadeクラスを継承したIlluminate\Support\Facades\Routeクラスにも、親クラスであるFacadeクラスにも、呼ばれたstaticメソッド(今回はget())が存在しない場合、マジックメソッドであるこの__callStaticメソッドが実行される。
つまり、↓が実行される。
public static function getFacadeRoot()
{
return static::resolveFacadeInstance(static::getFacadeAccessor());
//引数には文字列「router」が入る。
}
↓
protected static function resolveFacadeInstance($name)
{
if (is_object($name)) {
return $name; //オブジェクトだったらオブジェクトを返す
}
if (isset(static::$resolvedInstance[$name])) {
return static::$resolvedInstance[$name]; //インスタンスかどうか?→false
}
return static::$resolvedInstance[$name] = static::$app[$name];
//static::$appはヘルパーメソッドapp()と同じ動作を行う。
//文字列が入っていれば、文字列をもって解決したインスタンスを返す
//app()->make('router')と同じ。
}
⑤/vendor/laravel/framework/src/Illuminate/Foundation/Application.php
※↓の内容は、サービスコンテナの中身(?)。ここまで深堀しなくても、ヘルパー関数のapp()で確認することができます。bindメソッドを実行する前にweb.phpファイルの中でdd(app())を実行してサービスコンテナの中身を確認しておきます。
public function registerCoreContainerAliases()
{
foreach ([
'router' => [\Illuminate\Routing\Router::class,
\Illuminate\Contracts\Routing\Registrar::class,
\Illuminate\Contracts\Routing\BindingRegistrar::class],
] as $key => $aliases) {
foreach ($aliases as $alias) {
$this->alias($key, $alias);
}
}
}
⇒実際には、Illuminate\Routing\Router のインスタンスの get() が実行されている。
https://reffect.co.jp/laravel/laravel-facade-understanding#i
https://reffect.co.jp/laravel/laravel-service-container-understand
⑥/vendor/laravel/framework/src/Illuminate/Routing/Router.php
public function get($uri, $action = null)
{
return $this->addRoute(['GET', 'HEAD'], $uri, $action);
}
https://laravel10.wordpress.com/2015/04/27/%E3%83%95%E3%82%A1%E3%82%B5%E3%83%BC%E3%83%89/
・ファサードを使うメリット
①サービスコンテナを介してインスタンスにアクセスする為、テストを記述する時に、モックに入替えることが出来ます。
②Laravelの機能を簡素で覚えやすい文法で使ってもらえる
③ファサードは依存性注入の1つの方法です。依存性注入を使うと柔軟性、保守性が上がります。
④サービスコンテナを介してインスタンスにアクセスする為、オブジェクトをシングルトンとして登録できます。毎回クラスを new するのに比べて、メモリー効率、パフォーマンス効率が上がります。
https://laravel10.wordpress.com/2015/04/27/%E3%83%95%E3%82%A1%E3%82%B5%E3%83%BC%E3%83%89/
・契約 VS ファサード
同じような機能だけど用途が違う?
①「依存注入の最大の利便性は、注入するクラスの実装を入れ替えられるという機能です。モックやスタブを注入し、そうした代替オブジェクトの様々なメソッドのアサートが行えるため、テスト中に便利です。」
①-1 スタブ stubとは?
受信メッセージのテストに使う。
テストで注目しているオブジェクトが依存するものを、決まりきった動きしかしない偽物に置き換え、テストの合否が注目しているオブジェクト実装の正しさだけに依存するようにすること
①-2 モック とは?
送信メッセージのテストに使う。
メッセージの受け手を偽物にすり替えておき、この偽物にメッセージの引数や呼び出し回数が想定通りか検証させる。