$app = new Illuminate\Foundation\Application( realpath(__DIR__.'/../') ); public function __construct($basePath = null) { if ($basePath) { // 设置基础路径 $this->setBasePath($basePath); } // 基础绑定 $this->registerBaseBindings(); // 注册基础服务 $this->registerBaseServiceProviders(); // 核心容器别名设置 $this->registerCoreContainerAliases(); }
1.1 设置基础路径php
public function setBasePath($basePath) { $this->basePath = rtrim($basePath, '\/'); $this->bindPathsInContainer(); return $this; } protected function bindPathsInContainer() { $this->instance('path', $this->path()); $this->instance('path.base', $this->basePath()); $this->instance('path.lang', $this->langPath()); $this->instance('path.config', $this->configPath()); $this->instance('path.public', $this->publicPath()); $this->instance('path.storage', $this->storagePath()); $this->instance('path.database', $this->databasePath()); $this->instance('path.resources', $this->resourcePath()); $this->instance('path.bootstrap', $this->bootstrapPath()); } public function instance($abstract, $instance) { // 移除 abstractAliases $this->removeAbstractAlias($abstract); // 移除 aliases unset($this->aliases[$abstract]); // 直接设置容器属性 $this->instances $this->instances[$abstract] = $instance; // 当从新绑定时,进行从新构建 if ($this->bound($abstract)) { $this->rebound($abstract); } } protected function removeAbstractAlias($searched) { if (! isset($this->aliases[$searched])) { return; } foreach ($this->abstractAliases as $abstract => $aliases) { foreach ($aliases as $index => $alias) { if ($alias == $searched) { unset($this->abstractAliases[$abstract][$index]); } } } }
数组 $this->instances 以下:laravel
$this->instances['path'] = '/var/www/laravel/app'; $this->instances['path.base'] = '/var/www/laravel'; $this->instances['path.lang'] = '/var/www/laravel/resources/lang'; $this->instances['path.config'] = '/var/www/laravel/config'; $this->instances['path.public'] = '/var/www/laravel/public'; $this->instances['path.storage'] = '/var/www/laravel/storage'; $this->instances['path.database'] = '/var/www/laravel/database'; $this->instances['path.resources'] = '/var/www/laravel/resources'; $this->instances['path.bootstrap'] = '/var/www/laravel/bootstrap';
1.2 基础绑定redis
protected function registerBaseBindings() { static::setInstance($this); // 设置静态访问方式 $this->instance('app', $this); $this->instance(Container::class, $this); }
一样追加 $this->instances 以下:bootstrap
$this->instances['app'] = object(Illuminate\Foundation\Application); $this->instances['Illuminate\Container\Container'] = object(Illuminate\Foundation\Application);
1.3 注册基础服务segmentfault
protected function registerBaseServiceProviders() { $this->register(new EventServiceProvider($this)); $this->register(new LogServiceProvider($this)); $this->register(new RoutingServiceProvider($this)); } public function register($provider, $options = [], $force = false) { // 已注册,则直接返回 if (($registered = $this->getProvider($provider)) && ! $force) { return $registered; } // 若传的是字符串,则直接建立对象 if (is_string($provider)) { $provider = $this->resolveProvider($provider); } // 服务提供者里若存在register方法,则直接自动调用 if (method_exists($provider, 'register')) { $provider->register(); } $this->markAsRegistered($provider); // 当应用已经彻底boot时,自动执行服务提供者里面的boot方法 if ($this->booted) { $this->bootProvider($provider); } return $provider; } public function getProvider($provider) { $name = is_string($provider) ? $provider : get_class($provider); // 从$this->serviceProviders中取出第一个符合closure的值 return Arr::first($this->serviceProviders, function ($value) use ($name) { return $value instanceof $name; // $value是否$name的对象 }); } protected function markAsRegistered($provider) { $this->serviceProviders[] = $provider; $this->loadedProviders[get_class($provider)] = true; } protected function bootProvider(ServiceProvider $provider) { // 存在则调用相应服务提供者的boot方法 if (method_exists($provider, 'boot')) { return $this->call([$provider, 'boot']); } }
通常状况下,服务提供者都会提供两个方法:register和boot(register先负责注册服务,boot则负责
随后的引导工做,此时能够调用前面已经注册的服务)。在注册服务提供者的时候,会相应的调用服务提供
者的register方法,而后再进行boot方法的调用。数组
生成数组以下:cookie
event: $this->bindings['events'] = [ 'concrete' => function ($app) { return (new Dispatcher($app))->setQueueResolver(function () use ($app) { return $app->make(QueueFactoryContract::class); }); } 'shared' => 'true', ]; log: $this->bindings['log'] = [ 'concrete' => function () { return function createLogger() { $log = new Writer( new Monolog($this->channel()), $this->app['events'] ); if ($this->app->hasMonologConfigurator()) { call_user_func($this->app->getMonologConfigurator(), $log->getMonolog()); } else { $this->{$this->{'configure'.ucfirst($this->handler()).'Handler'}($log)}($log); } return $log; } } 'shared' => 'true', ]; router: $this->bindings['router'] = [ 'concrete' => function ($app) { return new Router($app['events'], $app); }, 'shared' => 'true', ]; $this->bindings['url'] = [ 'concrete' => function ($app) { $routes = $app['router']->getRoutes(); $app->instance('routes', $routes); $url = new UrlGenerator( $routes, $app->rebinding( 'request', $this->requestRebinder() ) ); $url->setSessionResolver(function () { return $this->app['session']; }); $app->rebinding('routes', function ($app, $routes) { $app['url']->setRoutes($routes); }); return $url; }, 'shared' => 'true', ]; $this->bindings['redirect'] = [ 'concrete' => function ($app) { $redirector = new Redirector($app['url']); if (isset($app['session.store'])) { $redirector->setSession($app['session.store']); } return $redirector; }, 'shared' => 'true', ]; $this->bindings[ServerRequestInterface::class] = [ 'concrete' => function ($app) { return (new DiactorosFactory)->createRequest($app->make('request')); }, 'shared' => 'true', ]; $this->bindings[ResponseInterface::class] = [ 'concrete' => function ($app) { return new PsrResponse(); }, 'shared' => 'true', ]; $this->bindings[ResponseFactoryContract::class] = [ 'concrete' => function ($app) { return new ResponseFactory($app[ViewFactoryContract::class], $app['redirect']); }, 'shared' => 'true', ];
注意:session
在register方法中,您只能将事物绑定到 服务容器 。不该该在register方法中尝试注册任何事件监听 器,路由或者任何其余功能。不然,您可能会意外的使用到还没有加载的服务提供者提供的服务。
1.4 核心容器别名设置app
public function registerCoreContainerAliases() { $aliases = [ 'app' => [\Illuminate\Foundation\Application::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class], 'auth' => [\Illuminate\Auth\AuthManager::class, \Illuminate\Contracts\Auth\Factory::class], 'auth.driver' => [\Illuminate\Contracts\Auth\Guard::class], 'blade.compiler' => [\Illuminate\View\Compilers\BladeCompiler::class], 'cache' => [\Illuminate\Cache\CacheManager::class, \Illuminate\Contracts\Cache\Factory::class], 'cache.store' => [\Illuminate\Cache\Repository::class, \Illuminate\Contracts\Cache\Repository::class], 'config' => [\Illuminate\Config\Repository::class, \Illuminate\Contracts\Config\Repository::class], 'cookie' => [\Illuminate\Cookie\CookieJar::class, \Illuminate\Contracts\Cookie\Factory::class, \Illuminate\Contracts\Cookie\QueueingFactory::class], 'encrypter' => [\Illuminate\Encryption\Encrypter::class, \Illuminate\Contracts\Encryption\Encrypter::class], 'db' => [\Illuminate\Database\DatabaseManager::class], 'db.connection' => [\Illuminate\Database\Connection::class, \Illuminate\Database\ConnectionInterface::class], 'events' => [\Illuminate\Events\Dispatcher::class, \Illuminate\Contracts\Events\Dispatcher::class], 'files' => [\Illuminate\Filesystem\Filesystem::class], 'filesystem' => [\Illuminate\Filesystem\FilesystemManager::class, \Illuminate\Contracts\Filesystem\Factory::class], 'filesystem.disk' => [\Illuminate\Contracts\Filesystem\Filesystem::class], 'filesystem.cloud' => [\Illuminate\Contracts\Filesystem\Cloud::class], 'hash' => [\Illuminate\Contracts\Hashing\Hasher::class], 'translator' => [\Illuminate\Translation\Translator::class, \Illuminate\Contracts\Translation\Translator::class], 'log' => [\Illuminate\Log\Writer::class, \Illuminate\Contracts\Logging\Log::class, \Psr\Log\LoggerInterface::class], 'mailer' => [\Illuminate\Mail\Mailer::class, \Illuminate\Contracts\Mail\Mailer::class, \Illuminate\Contracts\Mail\MailQueue::class], 'auth.password' => [\Illuminate\Auth\Passwords\PasswordBrokerManager::class, \Illuminate\Contracts\Auth\PasswordBrokerFactory::class], 'auth.password.broker' => [\Illuminate\Auth\Passwords\PasswordBroker::class, \Illuminate\Contracts\Auth\PasswordBroker::class], 'queue' => [\Illuminate\Queue\QueueManager::class, \Illuminate\Contracts\Queue\Factory::class, \Illuminate\Contracts\Queue\Monitor::class], 'queue.connection' => [\Illuminate\Contracts\Queue\Queue::class], 'queue.failer' => [\Illuminate\Queue\Failed\FailedJobProviderInterface::class], 'redirect' => [\Illuminate\Routing\Redirector::class], 'redis' => [\Illuminate\Redis\RedisManager::class, \Illuminate\Contracts\Redis\Factory::class], 'request' => [\Illuminate\Http\Request::class, \Symfony\Component\HttpFoundation\Request::class], 'router' => [\Illuminate\Routing\Router::class, \Illuminate\Contracts\Routing\Registrar::class, \Illuminate\Contracts\Routing\BindingRegistrar::class], 'session' => [\Illuminate\Session\SessionManager::class], 'session.store' => [\Illuminate\Session\Store::class, \Illuminate\Contracts\Session\Session::class], 'url' => [\Illuminate\Routing\UrlGenerator::class, \Illuminate\Contracts\Routing\UrlGenerator::class], 'validator' => [\Illuminate\Validation\Factory::class, \Illuminate\Contracts\Validation\Factory::class], 'view' => [\Illuminate\View\Factory::class, \Illuminate\Contracts\View\Factory::class], ]; foreach ($aliases as $key => $aliases) { foreach ($aliases as $alias) { $this->alias($key, $alias); } } } public function alias($abstract, $alias) { $this->aliases[$alias] = $abstract; $this->abstractAliases[$abstract][] = $alias; }
生成数组以下:ide
$this->aliases['Illuminate\Foundation\Application'] = 'app'; $this->aliases['Illuminate\Contracts\Container\Container'] = 'app'; $this->aliases['Illuminate\Contracts\Foundation\Application'] = 'app'; $this->abstractAliases['app'][] = 'Illuminate\Foundation\Application'; $this->abstractAliases['app'][] = 'Illuminate\Contracts\Container\Container'; $this->abstractAliases['app'][] = 'Illuminate\Contracts\Foundation\Application'; ……
$app->singleton( Illuminate\Contracts\Http\Kernel::class, App\Http\Kernel::class ); $app->singleton( Illuminate\Contracts\Console\Kernel::class, App\Console\Kernel::class ); $app->singleton( Illuminate\Contracts\Debug\ExceptionHandler::class, App\Exceptions\Handler::class ); public function singleton($abstract, $concrete = null) { // $this->bind($abstract, $concrete, true); }
生成数组以下
$this->bindings['Illuminate\Contracts\Http\Kernel'] = [ 'concrete' => function ($container, $parameters = []) { return $container->make('App\Http\Kernel', $parameters); }, 'shared' => 'true', ]; $this->bindings['Illuminate\Contracts\Console\Kernel'] = [ 'concrete' => function ($container, $parameters = []) { return $container->make('App\Console\Kernel', $parameters); }, 'shared' => 'true', ]; $this->bindings['Illuminate\Contracts\Debug\ExceptionHandler'] = [ 'concrete' => function ($container, $parameters = []) { return $container->make('App\Exceptions\Handler', $parameters); }, 'shared' => 'true', ];
总结:
应用实例化的流程以下
设置基础路径($this->instances['path.*']) => 注册基础绑定($this->instances['app|Container']) => 注册基础服务($this->bindings[]) => 注册核心容器别名($this->aliases[],$this->abstractAliases[])。至此,应用的实例化完成。
服务容器
服务容器里面的服务绑定形式有bind、singleton、instance方式,singleton和bind的惟一差异是传入的share真假问题,经过share变量来肯定singleton只实例化一次。而instance绑定的就是已经实例化的对象。when则是经过上下文来进行绑定的,每次都会进行绑定和实例化。服务容器里面的服务调用方式:make方法、resolve全局函数、自动注入,都可以经过容器服务来解决依赖关系。