laravel配置文件的加载过程及门面facade的初始化过程和服务提供者的初始化

  之前也写过一些文章,也是在老司机的分析下,学习过来的,现在尝试自己看一看laravel的一些基础配置机器引导过程也没有那么吃力了。目前看的是laravel5.8的版本。

  从index.php开始,在加载完composer的配置文件autoload.php文件以后,实例化了$app。

 1 $app = require_once __DIR__.'/../bootstrap/app.php';、
 2 
 3 
 4 //让我们进入这个文件看一看,内容如下
 5 //相关注释已经去掉
 6 
 7 $app = new Illuminate\Foundation\Application(
 8     $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
 9 );
10 
11 $app->singleton(
12     Illuminate\Contracts\Http\Kernel::class,
13     App\Http\Kernel::class
14 );
15 
16 $app->singleton(
17     Illuminate\Contracts\Console\Kernel::class,
18     App\Console\Kernel::class
19 );
20 
21 $app->singleton(
22     Illuminate\Contracts\Debug\ExceptionHandler::class,
23     App\Exceptions\Handler::class
24 );
25 
26 return $app;
View Code

  这里注册了三个单例对象,但是还没有实例化,等到需要使用的时候在进行实例化,由于 Illuminate\Foundation\Application 这个类的对象本身就继承了 Illuminate\Container; 这个容器类,所以它也拥有容器一样的特性。

  分析上述代码,注册单件就不说了,实际上是为后面需要这个对象而做准备,只是需要稍微注意下第一个单件

1 //Illuminate\Contracts\Http\Kernel::class是一个接口,如果要make它则实际上make(实例化)的是它的实现类App\Http\Kernel::class
2 $app->singleton(
3     Illuminate\Contracts\Http\Kernel::class,
4     App\Http\Kernel::class
5 );
View Code

  好的进入 Illuminate\Foundation\Application 这个类的构造方法中,代码如下:

 1     public function __construct($basePath = null)
 2     {
 3         if ($basePath) {
 4             $this->setBasePath($basePath);
 5         }
 6 
 7         $this->registerBaseBindings();
 8         $this->registerBaseServiceProviders();
 9         $this->registerCoreContainerAliases();
10     }
View Code

  先指定根路径,然后注册基础绑定和基础的服务提供者,之后在注册容器中对象的一些别名方便引用。这里就直接看第三个方法吧,前两个方法暂时还没研究。

 1     public function registerCoreContainerAliases()
 2     {
 3         foreach ([
 4             'app'                  => [self::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class, \Psr\Container\ContainerInterface::class],
 5             'auth'                 => [\Illuminate\Auth\AuthManager::class, \Illuminate\Contracts\Auth\Factory::class],
 6             'auth.driver'          => [\Illuminate\Contracts\Auth\Guard::class],
 7             'blade.compiler'       => [\Illuminate\View\Compilers\BladeCompiler::class],
 8             'cache'                => [\Illuminate\Cache\CacheManager::class, \Illuminate\Contracts\Cache\Factory::class],
 9             'cache.store'          => [\Illuminate\Cache\Repository::class, \Illuminate\Contracts\Cache\Repository::class],
10             'config'               => [\Illuminate\Config\Repository::class, \Illuminate\Contracts\Config\Repository::class],
11             'cookie'               => [\Illuminate\Cookie\CookieJar::class, \Illuminate\Contracts\Cookie\Factory::class, \Illuminate\Contracts\Cookie\QueueingFactory::class],
12             'encrypter'            => [\Illuminate\Encryption\Encrypter::class, \Illuminate\Contracts\Encryption\Encrypter::class],
13             'db'                   => [\Illuminate\Database\DatabaseManager::class],
14             'db.connection'        => [\Illuminate\Database\Connection::class, \Illuminate\Database\ConnectionInterface::class],
15             'events'               => [\Illuminate\Events\Dispatcher::class, \Illuminate\Contracts\Events\Dispatcher::class],
16             'files'                => [\Illuminate\Filesystem\Filesystem::class],
17             'filesystem'           => [\Illuminate\Filesystem\FilesystemManager::class, \Illuminate\Contracts\Filesystem\Factory::class],
18             'filesystem.disk'      => [\Illuminate\Contracts\Filesystem\Filesystem::class],
19             'filesystem.cloud'     => [\Illuminate\Contracts\Filesystem\Cloud::class],
20             'hash'                 => [\Illuminate\Hashing\HashManager::class],
21             'hash.driver'          => [\Illuminate\Contracts\Hashing\Hasher::class],
22             'translator'           => [\Illuminate\Translation\Translator::class, \Illuminate\Contracts\Translation\Translator::class],
23             'log'                  => [\Illuminate\Log\LogManager::class, \Psr\Log\LoggerInterface::class],
24             'mailer'               => [\Illuminate\Mail\Mailer::class, \Illuminate\Contracts\Mail\Mailer::class, \Illuminate\Contracts\Mail\MailQueue::class],
25             'auth.password'        => [\Illuminate\Auth\Passwords\PasswordBrokerManager::class, \Illuminate\Contracts\Auth\PasswordBrokerFactory::class],
26             'auth.password.broker' => [\Illuminate\Auth\Passwords\PasswordBroker::class, \Illuminate\Contracts\Auth\PasswordBroker::class],
27             'queue'                => [\Illuminate\Queue\QueueManager::class, \Illuminate\Contracts\Queue\Factory::class, \Illuminate\Contracts\Queue\Monitor::class],
28             'queue.connection'     => [\Illuminate\Contracts\Queue\Queue::class],
29             'queue.failer'         => [\Illuminate\Queue\Failed\FailedJobProviderInterface::class],
30             'redirect'             => [\Illuminate\Routing\Redirector::class],
31             'redis'                => [\Illuminate\Redis\RedisManager::class, \Illuminate\Contracts\Redis\Factory::class],
32             'request'              => [\Illuminate\Http\Request::class, \Symfony\Component\HttpFoundation\Request::class],
33             'router'               => [\Illuminate\Routing\Router::class, \Illuminate\Contracts\Routing\Registrar::class, \Illuminate\Contracts\Routing\BindingRegistrar::class],
34             'session'              => [\Illuminate\Session\SessionManager::class],
35             'session.store'        => [\Illuminate\Session\Store::class, \Illuminate\Contracts\Session\Session::class],
36             'url'                  => [\Illuminate\Routing\UrlGenerator::class, \Illuminate\Contracts\Routing\UrlGenerator::class],
37             'validator'            => [\Illuminate\Validation\Factory::class, \Illuminate\Contracts\Validation\Factory::class],
38             'view'                 => [\Illuminate\View\Factory::class, \Illuminate\Contracts\View\Factory::class],
39         ] as $key => $aliases) {
40             foreach ($aliases as $alias) {
41                 $this->alias($key, $alias);
42             }
43         }
44     }
View Code

  主要是一些别名对应的对象,之后调用 $this->alias($key, $alias); 依次将这些别名添几件啊加到$this(也就是Illuminate\Foundation\Application类)的aliase属性中,看一下alias方法,做了双向关联。我这就不贴代码了。

  一层层返回,Illuminate\Foundation\Application的对象$app实例化完成,回到app.php,之后执行了一段代码 $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); 之前提到需要注意的那个单件就是它,实例化这个接口,实际上需要实例化的是 App\Http\Kernel::class 这个类,点进这个类的构造方法,由于这个类没有构造方法,于是将会调用这个类父类的构造方法即 Illuminate\Foundation\Http\Kernel; 这个类的构造方法,这里传入一个 \Illuminate\Contracts\Foundation\Application 对象和 \Illuminate\Routing\Router 对象,怎么实例化的实际上就是容器完成的工作了,不是本次讨论的重点,进入构造方法,主要是对对象中的一些属性进行赋值操作,其它的一些操作也不是本次讨论的重点。本次所关注的就是赋值这个操作, Illuminate\Foundation\Http\Kernel;  已经有了 \Illuminate\Contracts\Foundation\Application  对象,这是我们所关注的,回到index.php,看这段代码:

1 $response = $kernel->handle(
2     $request = Illuminate\Http\Request::capture()
3 );
View Code

  刚才实例化的类调用了handle方法,并传入了一个对象,这个对象也不是本次的重点,进入这个方法看一看:

 1     public function handle($request)
 2     {
 3         try {
 4             $request->enableHttpMethodParameterOverride();
 5 
 6             $response = $this->sendRequestThroughRouter($request);
 7         } catch (Exception $e) {
 8             $this->reportException($e);
 9 
10             $response = $this->renderException($request, $e);
11         } catch (Throwable $e) {
12             $this->reportException($e = new FatalThrowableError($e));
13 
14             $response = $this->renderException($request, $e);
15         }
16 
17         $this->app['events']->dispatch(
18             new Events\RequestHandled($request, $response)
19         );
20 
21         return $response;
22     }
View Code

  第一个方法看一下比较简单,也不是这次的重点,进入第二个方法 $response = $this->sendRequestThroughRouter($request); 代码如下:

    protected function sendRequestThroughRouter($request)
    {
        $this->app->instance('request', $request);

        Facade::clearResolvedInstance('request');

        $this->bootstrap();

        return (new Pipeline($this->app))
                    ->send($request)
                    ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
                    ->then($this->dispatchToRouter());
    }
View Code

  看到有个facade类调用的静态方法,可以看一下。

1     public static function clearResolvedInstance($name)
2     {
3         unset(static::$resolvedInstance[$name]);
4     }
View Code

  清除了静态属性中的某个值,这个方法实际上我也不确定是干什么的,但不会影响本次的探讨,回到上个方法,接着进入了一个十分重要的方法 $this->bootstrap(); ,我们进去这个方法看看。

1     public function bootstrap()
2     {
3         if (! $this->app->hasBeenBootstrapped()) {
4             $this->app->bootstrapWith($this->bootstrappers());
5         }
6     }
View Code

  还记得刚刚强调的$app对象吗,就在这里起作用了,先判断是否引导完成,没有则开始引导,我们进入这个引导的方法 $this->app->bootstrapWith($this->bootstrappers()); ,带了一些重要的参数过去。

1     protected function bootstrappers()
2     {
3         return $this->bootstrappers;
4     }
View Code

  参数如下,主要是一些类:

1     protected $bootstrappers = [
2         \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
3         \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
4         \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
5         \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
6         \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
7         \Illuminate\Foundation\Bootstrap\BootProviders::class,
8     ];
View Code

  然后进入我们的$app类中的 bootstrapWith 方法。

 1     public function bootstrapWith(array $bootstrappers)
 2     {
 3         $this->hasBeenBootstrapped = true;
 4 
 5         foreach ($bootstrappers as $bootstrapper) {
 6             $this['events']->dispatch('bootstrapping: '.$bootstrapper, [$this]);
 7 
 8             $this->make($bootstrapper)->bootstrap($this);
 9 
10             $this['events']->dispatch('bootstrapped: '.$bootstrapper, [$this]);
11         }
12     }
View Code

  再循环中,实例化了参数中每一个类,并调用这个类的bootstrap方法,于是我们在这个参数中看到了Fade: \Illuminate\Foundation\Bootstrap\RegisterFacades::class, ,进入这个类的bootstrap方法:

 1     public function bootstrap(Application $app)
 2     {
 3         Facade::clearResolvedInstances();
 4 
 5         Facade::setFacadeApplication($app);
 6 
 7         AliasLoader::getInstance(array_merge(
 8             $app->make('config')->get('app.aliases', []),
 9             $app->make(PackageManifest::class)->aliases()
10         ))->register();
11     }
View Code

  初始化了一些东西,同时把$app对象赋值给这个类作为静态属性,之前有说过,其它的facade调用的时候 都会创建一个对象,就是从这个属性中以数组的形式取出对象,细心可以发现\Illuminate\Contracts\Foundation\Application父类Illuminate\Container实际上已经实现了ArrayAccess接口,获取的时候实际上是调用这个方法。

1     public function offsetGet($key)
2     {
3         return $this->make($key);
4     }
View Code

  直接make的方式获取方法,之后的静态调用实际上是调用了Facade的魔术方法。

 1     public static function __callStatic($method, $args)
 2     {
 3         $instance = static::getFacadeRoot();
 4 
 5         if (! $instance) {
 6             throw new RuntimeException('A facade root has not been set.');
 7         }
 8 
 9         return $instance->$method(...$args);
10     }
View Code

  由此说明$app对于Facade的重要性,现在我们便知道它实在什么时候被初始化了。

  接着是配置加载,本来刚开始还没注意的,主要还是想看服务提供者的加载过程,看的过程中跳过了某些东西于是引起了我的思考,决定退回去看看到底是怎么回事,以下则是过程。

  在引导完facade以后,进入下一个类, \Illuminate\Foundation\Bootstrap\RegisterProviders::class, ,进入这个类的bootstrap方法:

1     public function bootstrap(Application $app)
2     {
3         $app->registerConfiguredProviders();
4     }
View Code

  实际上调用的还是 Illuminate\Contracts\Foundation\Application 类的registerConfiguredProviders()这个方法,进入这个方法。

 1     public function registerConfiguredProviders()
 2     {
 3         $providers = Collection::make($this->config['app.providers'])
 4                         ->partition(function ($provider) {
 5                             return Str::startsWith($provider, 'Illuminate\\');
 6                         });
 7 
 8         $providers->splice(1, 0, [$this->make(PackageManifest::class)->providers()]);
 9 
10         (new ProviderRepository($this, new Filesystem, $this->getCachedServicesPath()))
11                     ->load($providers->collapse()->toArray());
12     }
View Code

  这里使用了集合,集合还是不是很熟悉,但是在make方法中传入一个参数, $this->config['app.providers'] ,我查看了一下,发现这个类包括其父类都没有这个属性,但是我很好奇它是哪里来的,于是才有了标题中才有laravel中相关配置加载这一项,我打印了这个属性实际上它是 /Illuminate/Config/Repository.php 类的对象,但是它是何时被实例化的,又是何时被赋值给 $app->config 属性的,我并不知道,找了半天没有头绪,于是我不厚道的开启了XDEBUG 调试模式,在它的构造方法里打了断点,只要执行完构造方法,我就知道在哪里实例化了,于是我发现实在这个类中被实例化的 /Illuminate/Foundation/Bootstrap/LoadConfiguration.php ,方法如下:

 1     public function bootstrap(Application $app)
 2     {
 3         $items = [];
 4 
 5         // First we will see if we have a cache configuration file. If we do, we'll load
 6         // the configuration items from that file so that it is very quick. Otherwise
 7         // we will need to spin through every configuration file and load them all.
 8         if (file_exists($cached = $app->getCachedConfigPath())) {
 9             $items = require $cached;
10 
11             $loadedFromCache = true;
12         }
13 
14         // Next we will spin through all of the configuration files in the configuration
15         // directory and load each one into the repository. This will make all of the
16         // options available to the developer for use in various parts of this app.
17         $app->instance('config', $config = new Repository($items));
18 
19         if (! isset($loadedFromCache)) {
20             $this->loadConfigurationFiles($app, $config);
21         }
22 
23         // Finally, we will set the application's environment based on the configuration
24         // values that were loaded. We will pass a callback which will be used to get
25         // the environment in a web context where an "--env" switch is not present.
26         $app->detectEnvironment(function () use ($config) {
27             return $config->get('app.env', 'production');
28         });
29 
30         date_default_timezone_set($config->get('app.timezone', 'UTC'));
31 
32         mb_internal_encoding('UTF-8');
33     }
View Code

  与此同时实例化完以后还把对象赋值给了 $app->config ,其实稍微细心一点就已经发现是怎么回事了,但是我还是没转过弯来,于是在用XDEBUG 再次跳出这个方法,看看到底是谁执行的,跳出后,果然,调用这个类的方法已经贴出过了,就是 bootsrrapWith() 方法,而 /Illuminate/Foundation/Bootstrap/LoadConfiguration 和 \Illuminate\Foundation\Bootstrap\RegisterFacades::class 一样其实都是 $bootstrappers 中的一个属性,只是刚才被忽略掉了。说到这里,我进入到 /Illuminate/Foundation/Bootstrap/LoadConfiguration 类的 bootstrap() 方法中看看配置是怎么加载进来的吧,代码已在上方贴出。

  看了看引用属性的方式: $this->config['app.providers'] ,也是通过数组的方式引用,(刚刚有提到过,Facade使用的时候也是以数组形式获取对象),于是,可以看一下这个类的 offsetGet() 方法,其实是调用 $this->get($key); 进入 get() 方法

1     public function get($key, $default = null)
2     {
3         if (is_array($key)) {
4             return $this->getMany($key);
5         }
6 
7         return Arr::get($this->items, $key, $default);
8     }
View Code

  看到这里也就是说,这个类的核心属性就是item,回到刚才实例化的过程,进入了一个if语句,查了一下,item是不存在的,所以不用管,接着实例化对象之后,下面一段代码则是关键。

1         if (! isset($loadedFromCache)) {
2             $this->loadConfigurationFiles($app, $config);
3         }
View Code

  进入 loadConfigurationFiles($app, $config) 这个方法。

 1     protected function loadConfigurationFiles(Application $app, RepositoryContract $repository)
 2     {
 3         $files = $this->getConfigurationFiles($app);
 4 
 5         if (! isset($files['app'])) {
 6             throw new Exception('Unable to load the "app" configuration file.');
 7         }
 8 
 9         foreach ($files as $key => $path) {
10             $repository->set($key, require $path);
11         }
12     }
View Code

  这里又调用了 $files = $this->getConfigurationFiles($app); ,进入这个方法在看一下。

 1     protected function getConfigurationFiles(Application $app)
 2     {
 3         $files = [];
 4 
 5         $configPath = realpath($app->configPath());
 6 
 7         foreach (Finder::create()->files()->name('*.php')->in($configPath) as $file) {
 8             $directory = $this->getNestedDirectory($file, $configPath);
 9 
10             $files[$directory.basename($file->getRealPath(), '.php')] = $file->getRealPath();
11         }
12 
13         ksort($files, SORT_NATURAL);
14 
15         return $files;
16     }
View Code

     getConfigurationFiles() 这个方法使用工具类遍历了根目录下中config目录的所有以.php结尾的文件,将文件赋值给 $files ,返回值如下:

 1 array:13 [
 2   "app" => "D:\phpstudy_v8.0\laravel\laravel5.8\config\app.php"
 3   "auth" => "D:\phpstudy_v8.0\laravel\laravel5.8\config\auth.php"
 4   "broadcasting" => "D:\phpstudy_v8.0\laravel\laravel5.8\config\broadcasting.php"
 5   "cache" => "D:\phpstudy_v8.0\laravel\laravel5.8\config\cache.php"
 6   "database" => "D:\phpstudy_v8.0\laravel\laravel5.8\config\database.php"
 7   "filesystems" => "D:\phpstudy_v8.0\laravel\laravel5.8\config\filesystems.php"
 8   "hashing" => "D:\phpstudy_v8.0\laravel\laravel5.8\config\hashing.php"
 9   "logging" => "D:\phpstudy_v8.0\laravel\laravel5.8\config\logging.php"
10   "mail" => "D:\phpstudy_v8.0\laravel\laravel5.8\config\mail.php"
11   "queue" => "D:\phpstudy_v8.0\laravel\laravel5.8\config\queue.php"
12   "services" => "D:\phpstudy_v8.0\laravel\laravel5.8\config\services.php"
13   "session" => "D:\phpstudy_v8.0\laravel\laravel5.8\config\session.php"
14   "view" => "D:\phpstudy_v8.0\laravel\laravel5.8\config\view.php"
15 ]
View Code

  这个方法的过程不是本次讨论的重点,于是回退到调用这个方法的方法 loadConfigurationFiles() ,接着遍历了刚才的数组,然后给每个属性设置相应的值,我们可以看到配置文件下app.php中又providers这个数组,回到上一层 bootstrap(Application $app) 下面的方法我也没有看过,但是大体上,laravel 的大部分的配置基本上都加载完毕了。

  解决了刚才的疑问,继续看服务提供者吧,回到 registerConfiguredProviders() , 方法如下:

 1     public function registerConfiguredProviders()
 2     {
 3         $providers = Collection::make($this->config['app.providers'])
 4                         ->partition(function ($provider) {
 5                             return Str::startsWith($provider, 'Illuminate\\');
 6                         });
 7 
 8         $providers->splice(1, 0, [$this->make(PackageManifest::class)->providers()]);
 9 
10         (new ProviderRepository($this, new Filesystem, $this->getCachedServicesPath()))
11                     ->load($providers->collapse()->toArray());
12     }
View Code

  这里对获取到的配置处理了一下,暂时还没分析怎么处理的,打算全分析完了再回去仔细看看是怎么处理的,还有获取配置的文件操作,最后一行实例化了一个类 /Illuminate/Foundation/ProviderRepository ,并调用了这个类的 load() 方法,看了一下控制器,都是些赋值操作,之后再看 load() 方法。

 1     public function load(array $providers)
 2     {
 3         $manifest = $this->loadManifest();
 4 
 5         // First we will load the service manifest, which contains information on all
 6         // service providers registered with the application and which services it
 7         // provides. This is used to know which services are "deferred" loaders.
 8         if ($this->shouldRecompile($manifest, $providers)) {
 9             $manifest = $this->compileManifest($providers);
10         }
11 
12         // Next, we will register events to load the providers for each of the events
13         // that it has requested. This allows the service provider to defer itself
14         // while still getting automatically loaded when a certain event occurs.
15         foreach ($manifest['when'] as $provider => $events) {
16             $this->registerLoadEvents($provider, $events);
17         }
18 
19         // We will go ahead and register all of the eagerly loaded providers with the
20         // application so their services can be registered with the application as
21         // a provided service. Then we will set the deferred service list on it.
22         foreach ($manifest['eager'] as $provider) {
23             $this->app->register($provider);
24         }
25 
26         $this->app->addDeferredServices($manifest['deferred']);
27     }
View Code

  直奔重点,前面的也暂时不管了,因为有些服务提供者会有些特殊的操作或者配置,先看看普通的吧:

1         foreach ($manifest['eager'] as $provider) {
2             $this->app->register($provider);
3         }
View Code

  这个 $manifest 实际上就是构造方法传进来的providers数组,之后调用 $this->app->register($provider); 来注册,进入这个方法:

 1     public function register($provider, $force = false)
 2     {
 3         if (($registered = $this->getProvider($provider)) && ! $force) {
 4             return $registered;
 5         }
 6 
 7         if (is_string($provider)) {
 8             $provider = $this->resolveProvider($provider);
 9         }
10 
11         $provider->register();
12 
13         if (property_exists($provider, 'bindings')) {
14             foreach ($provider->bindings as $key => $value) {
15                 $this->bind($key, $value);
16             }
17         }
18 
19         if (property_exists($provider, 'singletons')) {
20             foreach ($provider->singletons as $key => $value) {
21                 $this->singleton($key, $value);
22             }
23         }
24 
25         $this->markAsRegistered($provider);
26 
27         if ($this->isBooted()) {
28             $this->bootProvider($provider);
29         }
30 
31         return $provider;
32     }
View Code

  这里调用了 $this->resolveProvider($provider); ,这个方法就是对这个provider进行实例化,之后调用服务提供者的register方法,然后对这个服务提供者对象进行一些初始化操作,这些操作官方文档就有介绍。之后有个判断, $this->isBooted() ,如果框架引导完成,就会调用这个方法,此时是还没有将所有的privider加载完成的,所以引导还没有完成,因此不会调用里面的 $this->bootProvider($provider); 方法,这个方法其实就是调用服务提供者对象的 boot() 方法,也就是说, boot() 方法会在所有服务提供者被实例化了才会调用(这里我暂时还没有考虑延时的服务提供者),正好对应了文档,可以在boot方法中添加指定类型的参数,因为所有的服务提供者都实例化了,相关类的绑定也已经加入到容器的属性中了,所以可以使用依赖注入相关属性。而服务提供者的 register() 不能添加相关类参数,并不是所有的绑定都已经加入到容器中了,所以在这个方法里面使用依赖注入可能会出现问题,这一点文档中也说了,所有服务提供者实例化完成后,接着就是调用boot方法了,回到 Illuminate\Foundation\Http\Kernel 中, $bootstrappers  还有最后一行, \Illuminate\Foundation\Bootstrap\BootProviders::class 进入到这个类的booststrap方法中,这个类就是负责调用所有服务容器的 boot() 方法:

1     public function bootstrap(Application $app)
2     {
3         $app->boot();
4     }
View Code

  它调用了$app的boot方法,进入到这个方法:

 1     public function boot()
 2     {
 3         if ($this->isBooted()) {
 4             return;
 5         }
 6 
 7         $this->fireAppCallbacks($this->bootingCallbacks);
 8 
 9         array_walk($this->serviceProviders, function ($p) {
10             $this->bootProvider($p);
11         });
12 
13         $this->booted = true;
14 
15         $this->fireAppCallbacks($this->bootedCallbacks);
16     }
View Code

  对于每个provider,它又调用了 $this->bootProvider($p); ,进入这个方法

1     protected function bootProvider(ServiceProvider $provider)
2     {
3         if (method_exists($provider, 'boot')) {
4             return $this->call([$provider, 'boot']);
5         }
6     }
View Code

  于是,我们看见,服务提供者的boot方法被调用了,至此,于是分析也就到此结束了。

  

 

posted on 2020-07-15 10:30  halt丶dodo  阅读(315)  评论(0)    收藏  举报

导航