LaravelのDI・サービス構造
Laravelのコードを触ってるとかなりの頻度で以下のようなコードを目にする。
$myService = app(MyService::class);
一体何がしたいのか?
サマリ
あるクラスのインスタンスを生成してもらうのがサービスコンテナ。
インスタンス生成のルールを定義するのがサービスプロバイダ。
UnitTestの際に包含関係のクラスをモックに差し替えたい時に、コードをいじらずに差し替えるための仕組みっぽい
LaravelにおけるDI(依存性の注入)は、Laravelがインスタンスを生成した場合に行われる
new Hoge()ではダメで、app()->make()によるインスタンス生成を行う必要がある。
ControllerやConsoleなどの、Laravelが勝手にインスタンスを作る物に関しては、DIが行われる。
なお、ModelはDIされないし、する概念もない。
DIで注入される側(中身の方)のことはサービスと呼ばれている。サービスプロバイダで登録する事で、DIの対象になる
サービスコンテナ
https://readouble.com/laravel/8.x/ja/container.html
Laravelでは、app(MyService::class) を呼び出すことで、サービスコンテナ(Laravelの実体インスタンスであるApplicationが継承している)から MyService のインスタンスを取得できる。
この概念をDIと呼んでいる
サービスコンテナから取得したインスタンスでは、コンストラクタ引数に書いたクラス(タイプヒント)が解決可能(インスタンス化可能)であれば、自動的にインスタンス化して注入する機能がある。
Controllerの各Actionに書いたRequestにインスタンスが格納されているのもこの機能による物
Model系のインスタンスではDIは行われない。これらはEloquantのクラスなので、管轄が異なる
ここで言う「サービス」は、特定の機能を担うクラスやコンポーネントのことを指す。
例えば、ログ出力、キャッシュ管理、メール送信、バリデーション、イベントディスパッチなどが該当する。
code:laravel
class MyLogger {}
class MyService {
protected $logger;
public function __construct(MyLogger $logger){
$this->logger = $logger;
}
}
app()->make(MyService::class); // $loggerにインスタンスが入った状態でMyServiceを得られる
app(MyService::class); // 実体はapp()->make(MyService::class);
この「引数に書かれたクラスは解決可能なら解決して生成する」アイデアは、メソッドでも行われる
App::call(function(MyService $service){});で、MyServiceが解決された状態でメソッドが実行される
Laravelのマニュアルにはこれは素晴らしいと書いている。
サービスプロバイダ
https://readouble.com/laravel/8.x/ja/providers.html
サービスコンテナが自動的にクラスを解決できない場合
依存性がある
インターフェース型
抽象クラス型
解決手順をサービスコンテナに教えるのがサービスプロバイダの役目
毎回インスタンスを生成する他にも、シングルトンとして前回インスタンスを使い回すような設定もサービスプロバイダで行える
app/Providersフォルダに置く事が多い。
また、作成したプロバイダはconfig/app.phpのprovidersに列挙しないと実行されない
このインスタンス作成手順の登録を、結合と呼んでいる
ファサード
https://readouble.com/laravel/8.x/ja/facades.html
サービスコンテナへアクセスする正規ルートはapp()であるが、App::environment()でサービスコンテナ(と言うかLaravelコア)のメソッドが呼べたりする。
サービスコンテナで解決したインスタンスのメソッドに対して、staticアクセスかのように呼び出しが出来る機能。
具体的な仕組みなどはこちら
https://qiita.com/minato-naka/items/095f2a1beec1d09f423e
マジックメソッドで呼び出しを受け付けた後、Laravel DIの仕組みでインスタンスを特定している
Laravel標準で提供していいるファサードとヘルパ関数の一覧は以下の通り
https://readouble.com/laravel/8.x/ja/facades.html#facade-class-reference
ヘルパ関数
https://readouble.com/laravel/8.x/ja/facades.html#helper-functions
ファサードの仕組みだけでは、毎回useを書く必要があり、面倒であるため、これを補完するヘルパ関数が存在する