LaravelのRouteクラスがグローバル空間で呼び出せる仕組み
最近Laravelを触っています。
で、LaravelだとURLと実行するアクションを関連付けるルーティング部分を
Route::get('/', function()
{
return 'Hello World';
});
こんなふうに、RubyのSinatraっぽくかけるんですよね。ところがこのRoute
というクラス、事前にuse
で使う名前空間の指定もしていないし、実際にどのPHPクラスが使われているかよくわからない。そこでソースを追ってみました。
エイリアス
フロントコントローラのpubic/index.php
を起点に読み始めていくと、
pubic/index.php
->bootstrap/start.php
->vendor/laravel/framework/src/Illuminate/Foundation/start.php
とファイルが読み込まれて、この中で、
$aliases = $config['aliases'];
AliasLoader::getInstance($aliases)->register();
ということをやっている。でregister
メソッドで$aliasesのデータつかってspl_autoload_register
関数を呼び出してオートローディングを設定している。$aliases
の内容はメインのコンフィグファイルconfig/app.php
にかかれていて、デフォルトは以下のようになっている。
'aliases' => array(
'App' => 'Illuminate\Support\Facades\App',
'Artisan' => 'Illuminate\Support\Facades\Artisan',
'Auth' => 'Illuminate\Support\Facades\Auth',
'Blade' => 'Illuminate\Support\Facades\Blade',
'Cache' => 'Illuminate\Support\Facades\Cache',
'ClassLoader' => 'Illuminate\Support\ClassLoader',
'Config' => 'Illuminate\Support\Facades\Config',
'Controller' => 'Illuminate\Routing\Controller',
'Cookie' => 'Illuminate\Support\Facades\Cookie',
'Crypt' => 'Illuminate\Support\Facades\Crypt',
'DB' => 'Illuminate\Support\Facades\DB',
'Eloquent' => 'Illuminate\Database\Eloquent\Model',
'Event' => 'Illuminate\Support\Facades\Event',
'File' => 'Illuminate\Support\Facades\File',
'Form' => 'Illuminate\Support\Facades\Form',
'Hash' => 'Illuminate\Support\Facades\Hash',
'HTML' => 'Illuminate\Support\Facades\HTML',
'Input' => 'Illuminate\Support\Facades\Input',
'Lang' => 'Illuminate\Support\Facades\Lang',
'Log' => 'Illuminate\Support\Facades\Log',
'Mail' => 'Illuminate\Support\Facades\Mail',
'Paginator' => 'Illuminate\Support\Facades\Paginator',
'Password' => 'Illuminate\Support\Facades\Password',
'Queue' => 'Illuminate\Support\Facades\Queue',
'Redirect' => 'Illuminate\Support\Facades\Redirect',
'Redis' => 'Illuminate\Support\Facades\Redis',
'Request' => 'Illuminate\Support\Facades\Request',
'Response' => 'Illuminate\Support\Facades\Response',
'Route' => 'Illuminate\Support\Facades\Route',
'Schema' => 'Illuminate\Support\Facades\Schema',
'Seeder' => 'Illuminate\Database\Seeder',
'Session' => 'Illuminate\Support\Facades\Session',
'SSH' => 'Illuminate\Support\Facades\SSH',
'Str' => 'Illuminate\Support\Str',
'URL' => 'Illuminate\Support\Facades\URL',
'Validator' => 'Illuminate\Support\Facades\Validator',
'View' => 'Illuminate\Support\Facades\View',
),
つまりRoute
クラスの実体はIlluminate\Support\Facades\Route
ということがわかる。
Laravelは自前で設定ファイルからオートローディングの登録を行うロジックをもっていて、それをつかってグローバル空間にクラスのエイリアスを作るという機能を実装していたわけだった。
※じつはIlluminate\Support\Facades\Route
にはルーティングに使用していた上記のget
メソッドは直接定義されておらず、ここからさらにFacade
という仕組みをつかって、別のクラスに実装を移しているのだけど割愛。
PHPでDSLっぽいこと
調べてみると、どうってことはない作りでした。でもこの仕組みは、クラスの実装はネームスペースで構造化された空間に定義でき、インターフェースのみグローバル空間に公開するというのが、うまく出来てると思う。これに無名関数を組み合わせることで、LaravelのRoute定義のような、Rubyの内部DSL的な記述をPHP上に表現しているのだな、とちょっと感心したのでした。
おしまい。