Laravelの処理の流れ
前回記事における、Laravelのディレクトリ構造のところで、全てのリクエストはpublicディレクトリへのアクセスで処理される、といった話をしました。一方、その後に「Hello World!」を表示させるために追記したweb.phpファイルは、routesディレクトリ内にあり、publicディレクトリとは違います。では、リクエスト処理とは別のディレクトリ内のweb.phpが、どのようにしてリクエストと結びついていくのでしょうか。この種明かしは、Laravelの処理の流れと関わってきます。まず、そこから説明を始めましょう。
処理の起点であるpublic/index.php
Laravelの処理の起点となるのは、publicディレクトリです。ということは例えば、「http://localhost/firstlaravel/public/」といったURLの場合、URLの末尾にファイル名が指定されていませんのでこのディレクトリ内のindex.phpが実行されます。
実際、pubicディレクトリ内を参照すると、図1のようになっており、index.phpが存在します。
では、前回の最後に行った「Hello World!」を表示させるためのURL、「http://localhost/firstlaravel/public/hello」の場合はどうなのでしょうか。実は、このURLの場合でもindex.phpが実行されます。
この「/hello」に限らず、public以下のURLは、cssファイルやJavaScriptファイル、画像ファイルなど、public配下に実在するファイル以外は全てこのindex.phpが実行される仕組みとなっています。それを可能にしているのが、.htaccessファイルです。.htaccessファイルとは、ディレクトリ単位でApacheの設定が行えるファイルです。
ところで、現在参照しているpublicディレクトリも含めてfirstlaravelディレクトリ内のファイルやフォルダ類は全てcomposerコマンドによって自動生成されたものです。そのため、.htaccessファイルも自動生成されており、設定内容もあらかじめ記述されています。
では、自動生成された.htaccessファイルの中身を見てみましょう。リスト1のようになっています。ただし、ここでは、index.phpが常に実行されるように設定を行っている部分のみを抜粋しています。
<IfModule mod_rewrite.c> # (1) 〜省略〜 RewriteEngine On # (1) 〜省略〜 RewriteCond %{REQUEST_FILENAME} !-d # (2) RewriteCond %{REQUEST_FILENAME} !-f # (3) RewriteRule ^ index.php [L] # (4) </IfModule> # (1)
(1)はmod_rewriteが有効な場合だけ設定を適用させるための記述です。
(2)と(3)のRewriteCondはURLの書き換えを行う条件を設定します。
%{REQUEST_FILENAME}は、今アクセスしてきたURLに対応したサーバー上のパス情報を表します。(2)の-dはディレクトリかどうかをチェックした結果を表し、(3)の-fはファイルかどうかをチェックした結果を表します。(2)も(3)も前に否定を表す!がついているので、「今アクセスしてきたURLに対応したサーバー上のパスに該当ディレクトリ、もしくはファイルが存在しない場合」という条件を表します。
この条件に合致した場合、(4)のRewriteRuleに記述したルールにのっとってリクエストを移管します。RewriteRuleは、最初に移管元のパスパターンを記述し、続けて移管先のパスパターンを記述します。ここでは移管元のパスパターンとして「^」を記述しています。「^」は行頭を表す記号で、例えば、「^こんにちは」というのは、「こんにちは」から始まる行を表します。その行頭記号の後ろに何も記述がない場合は「全ての行」を表します。移管先がindex.phpです。なお、(4)の最後の[L]は、URLの書き換え処理の終了を意味します。
(1)~(4)の記述によって、実在するファイルへのリクエストはそのままそのファイルをレスポンスとして返す一方、存在しないファイルやディレクトリへのリクエストは、全てindex.phpが実行される仕組みとなっているのです。
なお、.htaccessファイルをはじめとしてcomposerコマンドによって自動生成されたファイルは、必要なものを除き、基本的に自動生成されたままにしておいたほうが無難でしょう。
index.phpが実行されてからの流れ
さて、全てのリクエストに対してindex.phpが実行されることがわかったところで、次に進みましょう。このindex.phpの内容もあらかじめ記述されています。このindex.phpを起点としてさまざまな処理が行われていますが、おおむね以下の流れとなっています。
- オートロードファイルの読み込み
- アプリケーションインスタンスの生成
- HTTPカーネルによる処理
- リクエストのディスパッチ
以下、それぞれを簡単に紹介していきますが、あらかじめ図としてまとめておきます。
解説の途中途中で図2を参照してください。
1.オートロードファイルの読み込み
関連するファイルは、vendor/autoload.phpです。もちろん、このファイルも自動生成されています。
Laravelを利用したアプリ開発では、フレームワークが提供するさまざまなクラスを使います。これらのクラスには名前空間が付与されています。また、Laravelを利用したアプリ内で自作するクラスに対しても名前空間を付与します。これら名前空間が付与されたクラスを利用する場合は、ファイルの上部でuse宣言を記述します。さらに、それらのクラスが記述されたファイル類を自動で読み込むための「オートロード」を利用します(名前空間とオートロードに関しては、拙記事「PHPの名前空間とクラス名のエイリアス、オートロード」を参照してください)。
そのオートロード機能を提供しているファイルが自動生成されたvendor/autoload.phpです。これをまず読み込むことでさまざまなクラスが利用可能となります。
2.アプリケーションインスタンスの生成
関連するファイルは、bootstrap/app.phpです。このapp.php内ではLaravelの本体といえるクラスであるIlluminate\Foundation\Applicationのインスタンスを生成します。このApplicationインスタンスは、Laravel内でさまざまな機能を提供する部品を管理し、つなげる役割を果たします。
Laravelのドキュメントでは、このApplicationインスタンスのことを「glue=糊(のり)」、「サービスコンテナ」と呼んでいます。まさに部品(=サービス)を管理する入れ物(=コンテナ)であり、それらの部品と部品を「接着」する働きですね。
3.HTTPカーネルによる処理
次に、HTTPカーネルと呼ばれる部品に処理が渡されます。この時に、中心として働くファイルはapp/Http/Kernel.phpです。
このHTTPカーネルは、このアプリに必要なさまざまな設定情報や部品群を読み込んで2.で生成されたApplicationインスタンス=サービスコンテナに登録します。この時に読み込まれるものとして、「環境設定」「エラーハンドラー」「ミドルウェア」「サービスプロバイダ」などがあります。
これらがどういったものかはこの連載中に紹介していきますが、概略は前回のLaravelの特徴で紹介しています。ただ、「サービスプロバイダ」については書いていません。これは、現段階では、Laravelアプリの実行時に必要なクラスのインスタンスを提供してくれるもの、と思っておいてください。
これらさまざまな部品がHTTPカーネルによってサービスコンテナに登録されることによって、サービスコンテナを通じて利用可能となります。ただ、この段階ではあくまで部品の登録だけであり、各種クラスのインスタンスを生成するのはあくまで利用する段階だということです。これがサービスコンテナのいいところであり、この仕組みのおかげで、Laravelの重厚長大なクラス群が軽快に動くようになっているのです。
なお、この各種部品がサービスコンテナに登録され、利用可能になった状態を、Laravelでは「bootstraped」と表現しています。また、この利用可能な状態へと持っていくことを「bootstrapping」、サービスコンテナに登録される各種部品群を「bootstrappers」と表現します。
4.リクエストのディスパッチ
HTTPカーネルによって、さまざまな部品がサービスコンテナに登録され、さまざまな機能が利用できるようになって初めて、リクエストは、それ専用の処理に移管されます。この段階で参照されるのが「ルーティング情報」です。
ルーティング情報とは、リクエストのURLに対応してどのような処理が行われるかを表すものであり、これをroutes/web.phpに記述します。実はこのweb.phpが読み込まれるタイミングは、上記3.のHTTPカーネルがサービスプロバイダを登録する時です。サービスプロバイダを登録する際、ルーティングに関するサービスプロバイダであるapp/Providers/RouteServiceProvider.phpファイルが読み込まれます。その中でweb.phpファイルを読み込む処理が記述されています。
このweb.phpに、例えば、/helloに対応する処理を記述しておくと、そのURLでアクセスした時に、その処理が実行されるようになっています。