ルーティング周りを読んでいて気になった内部的なローディングのことを少し確認しておく。
laravelはたくさんのServiceProviderが提供するサービスを利用して動いている(?)
ServiceProviderをregisterすることで、色々なところから使える状態になる
https://github.com/laravel/framework/blob/4.2/src/Illuminate/Support/ServiceProvider.php#L44
以前読んだRoutingのServiceに加えて、Event, ExceptionはBaseServiceProviderとして特別扱いされていて、Applicationのコンストラクタで呼ばれてregisterされている
protected function registerBaseServiceProviders() { foreach (array('Event', 'Exception', 'Routing') as $name) { $this->{"register{$name}Provider"}(); } }
それ以外はstart.phpから。
https://github.com/laravel/framework/blob/4.2/src/Illuminate/Foundation/start.php#L208L210
$providers = $config['providers']; $app->getProviderRepository()->load($app, $providers);
このProviderRepositoryがeagerに読み込むかlazyに読み込むかなど振り分けつつ、ここでServiceProviderたちをregisterしている
registerは何をすることなのか。
Routingの場合は$app['router']にRouteをセットすることだった。
AuthServiceProvider
public function register() { $this->app->bindShared('auth', function($app) { // Once the authentication service has actually been requested by the developer // we will set a variable in the application indicating such. This helps us // know that we need to set any queued cookies in the after event later. $app['auth.loaded'] = true; return new AuthManager($app); }); }
CacheServiceProvider
public function register() { $this->app->bindShared('cache', function($app) { return new CacheManager($app); }); $this->app->bindShared('cache.store', function($app) { return $app['cache']->driver(); }); $this->app->bindShared('memcached.connector', function() { return new MemcachedConnector; }); $this->registerCommands(); }
CommandsServiceProvider
public function register() { $this->app->bindShared('command.session.database', function($app) { return new Console\SessionTableCommand($app['files']); }); $this->commands('command.session.database'); }
これらを見ているとbindShared
を呼び出すのがメインっぽい
bindShared
のやっていることはこれだけで、bind
を単にちょっとラップしてるだけ。offsetSet
からもbind
は呼ばれていて、ただその場合は第3引数が渡されないのでsharedがfalseになる。
public function bindShared($abstract, Closure $closure) { return $this->bind($abstract, $this->share($closure), true); }
bind
にClosureが渡されていない場合はgetClosure
というのが呼ばれる
protected function getClosure($abstract, $concrete) { return function($c, $parameters = array()) use ($abstract, $concrete) { $method = ($abstract == $concrete) ? 'build' : 'make'; return $c->$method($concrete, $parameters); }; }
結構Closureを多用している感あるなー。今回はclosureが渡されているので関係ないけど
aliasの設定とかゴニョゴニョしつつ
array( 'concrete' => Closure, 'shared' => bool )
な形で$appからアクセスできるように追加している。これがregisterということかな。
shared
は何に使われているのかまだ見ていないけど、$app
にブラケットでアクセスしようとすると、そのkeyでmake($key)
が呼ばれて、concreteのclosureを使って作られたインスタンスを取得できるという感じ。