Laravel 延迟服务提供者`provides` 未被调用

Jul*_*ian 6 php laravel-5 laravel-5.2

我有以下定义:

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\SomeClass;

class SomeProvider extends ServiceProvider
{
    protected $defer = true;

    public function register()
    {
        $this->app->bind(SomeClass::class, function ($app)
        {
            return new SomeClass();
        });
    }

    public function provides()
    {
        die("This never gets called");
        return [SomeClass::class];
    }
}
Run Code Online (Sandbox Code Playgroud)

并且它SomeClass按预期返回一个实例,除了根据文档,如果$defer为真,provides()则应调用该方法。无论我设置什么$defer,也无论我是否真的要求一个实例SomeClassprovides()都不会被调用。

我要求类的实例的方式如下:

App::make('SomeClass');
Run Code Online (Sandbox Code Playgroud)

fel*_*ins 7

简短回答:
您编译的清单文件已经由框架编译。

当 Laravel 第一次构建应用程序(并解析 IoC 容器中的所有服务提供者)时,它会写入名为services.php 的缓存文件(即清单文件,放在: 中bootstrap/cache/services.php)。
因此,如果您清除通过php artisan clear-compiled命令编译的内容,它应该强制框架重建清单文件,您可能会注意到provides调用了该方法。在下一个调用/请求provides方法不再被调用。

框架启动的顺序几乎是这样的:

//public/index.php
$app = new Illuminate\Foundation\Application(
    realpath(__DIR__.'/../')
);

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
    \Illuminate\Foundation\Http\Kernel::__construct();
    \Illuminate\Foundation\Http\Kernel::handle();
        \Illuminate\Foundation\Http\Kernel::sendRequestThroughRouter();
            \Illuminate\Foundation\Http\Kernel::bootstrap();
                \Illuminate\Foundation\Application::bootstrapWith();
                    # where $bootstrapper is a item from \Illuminate\Foundation\Http\Kernel::$bootstrappers 
                    # and $this is instance of \Illuminate\Foundation\Application
                    \Illuminate\Foundation\Application::make($bootstrapper)->bootstrap($this);
Run Code Online (Sandbox Code Playgroud)

引导程序之一是Illuminate\Foundation\Bootstrap\RegisterProviders调用\Illuminate\Foundation\Application::registerConfiguredProviders(),然后调用 \Illuminate\Foundation\ProviderRepository::__construct(),最后:

\Illuminate\Foundation\ProviderRepository::load()

\Illuminate\Foundation\ProviderRepository::load()被调用时,所有服务提供者\Illuminate\Support\ServiceProvider::provides()都已注册并且 也被很好地调用。

这是您应该知道的片段(来自\Illuminate\Foundation\ProviderRepository::load):

    /**
     * Register the application service providers.
     *
     * @param  array  $providers
     * @return void
     */
    public function load(array $providers)
    {
        $manifest = $this->loadManifest();

        // First we will load the service manifest, which contains information on all
        // service providers registered with the application and which services it
        // provides. This is used to know which services are "deferred" loaders.
        if ($this->shouldRecompile($manifest, $providers)) {
            $manifest = $this->compileManifest($providers);
        }

        // Next, we will register events to load the providers for each of the events
        // that it has requested. This allows the service provider to defer itself
        // while still getting automatically loaded when a certain event occurs.
        foreach ($manifest['when'] as $provider => $events) {
            $this->registerLoadEvents($provider, $events);
        }

        // We will go ahead and register all of the eagerly loaded providers with the
        // application so their services can be registered with the application as
        // a provided service. Then we will set the deferred service list on it.
        foreach ($manifest['eager'] as $provider) {
            $this->app->register($this->createProvider($provider));
        }

        $this->app->addDeferredServices($manifest['deferred']);
    }
Run Code Online (Sandbox Code Playgroud)

\Illuminate\Foundation\ProviderRepository::compileManifest()provides()是执行您的方法的地方。