Laravel 5 の処理の流れ

Laravel

前回 Laravel 5 の Global Middleware ではルートの名前がとれない? の疑問をきっかけに、Laravel 5 の処理の流れを追ってみましたのでメモしておきます。

バージョン

Laravel Framework version 5.0.6

処理の流れ

タマネギ構造

最初のBootstrapな処理(アプリケーションを開始するための準備的な処理)と、最後にレスポンスを返す処理の間が、各Middleware(「Global Middleware」と「ルートに割り当てられたMiddleware」の2種類) の前処理と後処理で包まれたタマネギ構造になっています。

Middlewareのタマネギ構造を強調して処理の流れを書くと以下のような感じです。

  • Bootstrapな処理
    • Global Middleware(1番目)の前処理
    • Global Middleware(2番目)の前処理
    • :
    • Global Middleware(m番目)の前処理
      • ルートに割り当てられたMiddleware(1番目)の前処理
      • ルートに割り当てられたMiddleware(2番目)の前処理
      • :
      • ルートに割り当てられたMiddleware(n番目)の前処理
        • コントローラの処理(レスポンスの生成まで)
      • ルートに割り当てられたMiddleware(n番目)の後処理
      • ルートに割り当てられたMiddleware((n-1)番目)の後処理
      • :
      • ルートに割り当てられたMiddleware(1番目)の後処理
    • Global Middleware(m番目)の後処理
    • Global Middleware((m-1)番目)の後処理
    • :
    • Global Middleware(1番目)の後処理
  • クライアントにレスポンスを出力
  • Global Middlewareのterminate処理

※「ルートに割り当てられたMiddleware」は、アクセスされたルートに割り当てられていたMiddlewareのみが実行されます。

もう少し詳しく

それぞれの処理をもう少し詳しく書くと、以下のようになります。上から順番に処理が進みます(HTTPアクセスの場合)。

  • \Illuminate\Foundation\Application のインスタンスの生成処理
  • \Illuminate\Foundation\Http\Kernel のインスタンスの生成処理
  • \Illuminate\Foundation\Http\Kernelのhandleメソッド実行
    • \Illuminate\Foundation\Http\Kernelのbootstrapメソッド実行
      • 以下のクラスの処理が実行される。
      • Illuminate\Foundation\Bootstrap\DetectEnvironment
      • Illuminate\Foundation\Bootstrap\LoadConfiguration
      • Illuminate\Foundation\Bootstrap\ConfigureLogging
      • Illuminate\Foundation\Bootstrap\HandleExceptions
      • Illuminate\Foundation\Bootstrap\RegisterFacades
      • Illuminate\Foundation\Bootstrap\RegisterProviders
        • サービスプロバイダーのregister() が実行される。
      • Illuminate\Foundation\Bootstrap\BootProviders
        • サービスプロバイダーのboot() が実行される。
    • Global Middleware のパイプライン処理(Global Middlewareを順番に実行する)
      • app/Http/Kernel.php 内の $middleware プロパティに登録された Middleware の最後に、Router の dispatch処理(を内部に含んだクロージャ)が加えられた形で、これらが順番に実行される。これはタマネギ構造になっており、それぞれの前処理を順番に実行し終えたら(最後のRouterのdispatch処理は、下で示すようにレスポンスの生成まで行っている)、今度は逆順で各middlewareの後処理(あれば)が実行される。
      • デフォルトで登録されている Global Middleware
        • Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode
        • Illuminate\Cookie\Middleware\EncryptCookies
        • Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse
        • Illuminate\Session\Middleware\StartSession
        • Illuminate\View\Middleware\ShareErrorsFromSession
        • App\Http\Middleware\VerifyCsrfToken
      • Router の dispatch処理の内容(Global Middlewareの最後の要素として実行される)
        • ルートが決定
        • Route Model Biding を実行
        • 「ルートに割り当てられたMiddleware」のパイプライン処理(「ルートに割り当てられたMiddleware」が実行される)(これもタマネギ構造になっていて、前処理 → 折り返し → 後処理の順番で実行される)。このパイプラインの最後の要素がコントローラの処理になっている。
          • コントローラの処理の内容
            • コントローラメソッドのインジェクション処理
            • コントローラのコンストラクタの実行(インジェクション処理含む)
            • コントローラメソッド実行
            • レスポンスのオブジェクトが生成されるところまで実行する。(クライアントにレスポンスを出力する直前までの処理が実行される)
        • 「ルートに割り当てられたMiddleware」の後処理(あれば)が逆順で実行
      • Global Middlewareの後処理(あれば)が逆順で実行
  • クライアントにレスポンスが出力される。
  • Global Middleware の terminateメソッド実行(TerminableMiddlewareインタフェースを実装しているもののみ)

以上のようにかなりシンプルな構造になっていて、上記の1階層目の処理は public/index.php の中にほぼそのまま記述されています。

この順番を見ると、前回(Laravel 5 の Global Middleware ではルートの名前がとれない?)書いたように、Global Middlewareの前処理が実行される時点ではルートが決定していませんので、名前付きルートの名前が取得できないのも納得できます。

また、「ルートに割り当てられたMiddleware」は Route Model Binding の後で実行されることが分かります。このため、Route Model Binding で認証済みのユーザしか持っていない値を使っている場合には注意が必要で、目的の Route Model Binding が発生するルートに 'auth' の Middleware(「ルートに割り当てられたMiddleware」として登録されています)を割り当てていても、実際には認証していない状態で処理が実行されてしまう可能性があります。

他にもMiddlewareの実行されるタイミングだと不便なことがあるかもしれませんが、その場合はイベントリスナーを登録して処理を実行させるなりした方がいいかもしません。

補足

Middlewareの前処理と後処理について

以下は、Middleware の handleメソッドです。前処理は $next($request) の前に書き、後処理は後ろに書きます。

public function handle($request, Closure $next)
{
  //-------------------------------------------------
  // 前処理はここに書く(コントローラの処理の前に実行される)
  //-------------------------------------------------
  $response = $next($request);
  //-------------------------------------------------
  // 後処理はここに書く(レスポンスが生成された後で実行される)
  //-------------------------------------------------
  return $response;
}

最終更新日: 2015-2-25

Pocket

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*