$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全局函數、自動注入,都可以經過容器服務來解決依賴關係。