0
0

More than 3 years have passed since last update.

Laravel はじめました [3. 構成の概念]

Last updated at Posted at 2021-03-18

※前回の記事は以下です

概要

リクエストのライフサイクル

概論

  • リクエストの受け口は public/index.php のみ
    • Composerが生成したオートローダーの定義をロードする
    • bootstrap/app.php からアプリケーション/サービスコンテナのインスタンスを取得する

HTTP/Consoleカーネル

  • app/Http/Kernel.php
    • 送信されたリクエストを渡され、処理する。全リクエストフローの中心に位置し動作する
    • Illuminate\Foundation\Http\Kernel クラスを継承し拡張している
    • エラー処理、ログ設定、アプリケーション動作環境の決定、そのほか実際にリクエストが処理される前に行う必要のあるタスクなどのbootstrappers(起動コード)の配列を定義する
    • HTTPセッションの読み書き、アプリケーションがメンテナンスモードであるかの決定、CSRFトークンの確認などのHTTPミドルウェアのリストも定義する
  • サービスプロバイダ
    • config/app.php ファイルの providers 配列で設定されている
      • 親クラス Illuminate\Foundation\Http\Kernel に定義されている $bootstrappers の中に角サービスプロバイダが登録されている
    • サービスプロバイダはデータベース、キュー、バリデーション、ルーティングなど、フレームワークの様々なコンポーネントの初期起動処理に責任をもつ
    • カーネルの handle メソッド内で実行されている
    • プロバイダーを自作する場合は app/Providers に作成すること
  • リクエストのディスパッチ
    • ルーターはそのリクエストをルートかコントローラにディスパッチし、その時にルートに指定されているミドルウェアも実行する
    • これも、カーネルの handle メソッド内で実行されている

サービスコンテナ

結合

  • シンプルな結合

    • コンテナ自身がリゾルバ―の引数として渡される(=第二引数に渡すクラス名を、第一引数に文字列として指定する)
    • 意味としては、app()->bind('呼び出しキーワード', 'インスタンス化方法');

      $this->app->bind('HelpSpot\API', function ($app) {
          return new HelpSpot\API($app->make('HttpClient'));
      });
      
    • 他の結合方法との違いが説明できない。。。

      • make() が呼ばれる度に都度インスタンス生成する(=シングルトンでない)
  • シングルトン結合

    • 一度シングルトン結合が解決されるとそれ以降、この結合が参照されるたび、コンテナは同じオブジェクトインスタンスを返す

      $this->app->singleton('hogehoge', function ($app) {
          return new HelpSpot\API($app->make('HttpClient'));
      });
      
  • インスタンス結合

    • 既に存在するオブジェクトのインスタンスをコンテナに結合する
    • 以降の呼び出しには、登録したインスタンスが返される

      $api = new HelpSpot\API(new HttpClient);
      $this->app->instance('foobar', $api);
      
  • プリミティブ結合

    • プリミティブな値をコンテナに登録できる

      $this->app->when('App\Http\Controllers\UserController')
                ->needs('$variableName')
                ->give($value);
      
    • 具体的な呼び出し方は?

      • コントローラー側でのコンストラクタで型を指定すれば、依存解決機能を使って自動的にインスタンス化して渡してくれる
      • もしくは、app()->make('hogehoge'); でインスタンス化する

インターフェイスと実装の結合

  • 呼び出しキーワードにインターフェースを指定して具象クラスをインスタンス化したい場合、省略して書けるよ

コンテキストによる結合

  • when()->needs()->give() を使えば、同じキーワードでも呼び出し元に沿ったインスタンスを返すよ

タグ付け

  • tag() を使えば、タグ付けした一連のサービスを tagged() で取得できるよ

結合の拡張

  • extend() でサービスの解決結果を修正できるよ

依存解決

  • makeメソッド

    • $this->app->make('HelpSpot\API'); で、コンテナに結合されたサービスをインスタンス化するよ
    • $app変数へアクセスできない場所なら、resolve('HelpSpot\API'); でいけるよ
    • makeWith() は具体的にどこで使うの?
  • 自動注入

    • 以下のコンストラクタでは、自動的に型解決してインスタンスが注入されるよ
      • コントローラ
      • イベントリスナ
      • キュージョブ
      • ミドルウェア
    • コントローラーのコンストラクタで使用するリポジトリを受け取る、なんかはこの仕組みで受け取ってるよ

コンテナイベント

  • コンテナが解決された に実行する関数を定義できる
    • コールバック関数と考えてよさそう
  • すべてのコンテナが解決された時に実行する
    • $this->app->resolving(function ($object, $app) {});
  • 特定のコンテナが解決された時に実行する
    • $this->app->resolving(HelpSpot\API::class, function ($api, $app) {});

PSR-11

サービスプロバイダ

  • 初期起動処理を行う心臓部
    • サービスコンテナの結合や、イベントリスナ、フィルター、それにルートなどを登録することを指す
  • config/app.php にデフォルトのサービスプロバイダが定義されているよ
    • いっぱいあるけど、ほとんどは遅延ロードだよ
  • 実際に手を動かした内容は このコミット を参照

サービスプロバイダの記述

  • Illuminate\Support\ServiceProvider を継承しましょうね
  • register と boot の 2 つのメソッドを持つ
    • register ではサービスコンテナの登録 のみ を行うこと
      • なんで?
        • サービスプロバイダがまだロードしていないサービスを意図せず使ってしまうこともありえるから
        • ルールとして「そうしましょうね」ということ。守らないと意図しないエラーが起こる可能性がありますよ
  • 以下コマンドでプロバイダを新規作成できるよ

    $ php artisan make:provider RiakServiceProvider
    
  • Registerメソッド

    • 一つずつ $app から登録してもいいけど、$bindings$singletons プロパティを宣言すれば、それぞれのプロパティの中身を自動で登録してくれるよ
  • Bootメソッド

    • 他の全サービスプロバイダが登録し終えてから呼び出されるよ
    • ビューコンポーサの登録やサービスコンテナ使って処理したい場合はここに記述するよ
    • 依存解決もしてくれるから、引数を追加すれば自動でインスタンスを受け取れるよ

プロバイダの登録

  • サービスプロバイダを新規作成したら config/app.php$providers プロパティに追加しましょうね

遅延プロバイダ

  • サービスコンテナの登録 だけ を目的とするなら、遅延ロードさせた方がパフォーマンスは良いよね
  • サービスプロバイダにて、以下を行うと指定した結合は遅延ロードさせれるよ
    1. protected $defer = true; を宣言
    2. provides() メソッドを定義して、結合名の配列を返却する

ファサード

いつファサードを使うか

  • ファサードを定義しまくって一つのコントローラで呼び出しまくると、そのコントローラの責任が大きくなるから良くないよ、という話
  • ファサード 対 依存注入
    • 依存注入は、実行環境などの諸条件でモックを使用できるから便利だよね
    • でも、ファサードで呼び出すメソッドは「実行環境などの諸条件でモックを使用」したものに対しても実行できるから、ファサードも負けて無いよ、ということかな。
  • ファサード 対 ヘルパ関数
    • ファサードとヘルパ関数は同じ使い方ができるよ、という話

ファサードの仕組み

  • 冒頭にも書いたけど、__callStatic() マジックメソッドにより実現してますよ
  • 以下コマンドでコントローラを作って、ドキュメント通りに実装してみた
    • $ php artisan make:controller UserController
  • サービスコンテナに登録したクラスをファサードとして使用するには、
    1. Illuminate\Support\Facades\ にクラスを作る
    2. [1.] のクラスには getFacadeAccessor() メソッドのみ定義し、サービスコンテナに登録された結合名を返す
    3. config/app.phpaliases に [1.] を登録する

リアルタイムファサード

  • 以下コマンドでモデルを作って、ドキュメント通りに実装してみた
    • $ php artisan make:model Podcast
  • [ファサードの仕組み]でやったような手順を踏まなくても、特定のクラスをファサードクラスとして使用できるよ、という話
  • テスト方法も書いてあるが、少しめんどくさそう。モックを注入する方がわかり良いのではないか。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0