【laravel 实现杂谈】ServiceProvider -- 初始化 - (sunznx) 振翅飞翔
06 September 2019

laravel 框架在初始化时,在 Illuminate/Foundation/Application.php 的如下代码就会开始处理 ServiceProvider 的相关逻辑

(new ProviderRepository($this, new Filesystem, $this->getCachedServicesPath()))
    ->load($providers->collapse()->toArray());

Illuminate/Foundation/ProviderRepository.php

public function load(array $providers)
{
    $manifest = $this->loadManifest();

    if ($this->shouldRecompile($manifest, $providers)) {
        $manifest = $this->compileManifest($providers);
    }

    foreach ($manifest['when'] as $provider => $events) {
        $this->registerLoadEvents($provider, $events);
    }

    foreach ($manifest['eager'] as $provider) {
        $this->app->register($provider);
    }

    $this->app->addDeferredServices($manifest['deferred']);
}

上面两段代码的大概解释如下:
getCachedServicesPath() 的路径是 bootstrap/cache/services.php, 这个文件的内容是依赖于 bootstrap/cache/packages.php 来生成的, bootstrap/cache/packages.php 的相关生成方式在 【laravel 实现杂谈】Package Discovery 有一丁点的介绍。

简单来讲就是 cache/packages.php 记录了 laravel 运行的时候需要哪些 ServiceProvider。
然后在 ProviderRepository 里面会将这些 ServiceProvider 进行再次分类,分类成三种 when, eager, deferred
怎么分?实际上也只是简单的 new XXXServiceProvider ,然后判断生成的 instance 有没有 deferred, when 等属性,如果没有的话就是 eager(默认)
最后再将分类好的 class 写入到 cache/services.php 里面,内容大概如下:

<?php return array (
    'providers' => array (
        0 => 'Illuminate\\Auth\\AuthServiceProvider',
        1 => 'Illuminate\\Broadcasting\\BroadcastServiceProvider',
        2 => 'Illuminate\\Bus\\BusServiceProvider',
        ...
    ),
    'eager' => array (
        0 => 'Illuminate\\Auth\\AuthServiceProvider',
        1 => 'Illuminate\\Cookie\\CookieServiceProvider',
        ...
    ),
    'deferred' => array (
        ...
    ),
    'when' => array (
        ...
    ),
    ...
);