Laravel服务提供商说明


Laravel service provider explanation

我对Laravel Service provider不太熟悉,我有一个问题。

示例:我有三个类SystemProfiler, SurveyProfiler和OfferProfiler实现ProfilerInterface。我还有ProfilerService类它在构造函数中注入ProfilerInterface。我需要创建不同的ProfilerService服务,并注入每个分析器。

ProfilerService:

class ProfilerService {
    $this->profiler;
    function __construct(ProfilerInterface $profiler) {
            $this->profiler = profiler;
    }
}

我知道如何在symfony2框架中这样做:

system_profiler:
    class: App'MyBundle'Profiles'SystemProfiler
survey_profiler:
    class: App'MyBundle'Profiles'SurveyProfiler
offer_profiler:
    class: App'MyBundle'Profiles'OfferProfiler
system_profile_service:
    class: App'MyBundle'Services'ProfilerService
    arguments:
        - system_profiler
survey_profile_service:
    class: App'MyBundle'Services'ProfilerService
    arguments:
        - survey_profiler
offer_profile_service:
    class: App'MyBundle'Services'ProfilerService
    arguments:
        - offer_profiler

然后用ProfilerService实现的别名调用$this->container->get()

但是Laravel文档说"如果类不依赖于任何接口,就没有必要将它们绑定到容器中。"。ProfilerService不依赖于接口。因此,我可以像这样将每个分析器绑定到接口:

   $this->app->bind('App'MyBundle'Contracts'ProfilerInterface','App'MyBundle'Profiles'SystemProfiler');

$this->app->bind('App'MyBundle'Contracts'ProfilerInterface','App'MyBundle'Profiles'SurveyProfiler');

$this->app->bind('App'MyBundle'Contracts'ProfilerInterface','App'MyBundle'Profiles'OfferProfiler');

但是我应该如何绑定哪个分析器应该注入ProfilerService以及何时??

我将感谢任何帮助和解释

开始了(阅读文档):

// ServiceProvider
public function register()
{
    // Simple binding
    $this->app->bind('some_service.one', 'App'ImplOne::class);
    $this->app->bind('some_service.two', 'App'ImplTwo::class);
    // Aliasing interface - container will inject some_service.one
    // whenever interface is required...
    $this->app->alias('some_service.one', 'App'SomeInterface::class);
    // ...except for the Contextual Binding:
    $this->app->when('App'DependantTwo::class)
              ->needs('App'SomeInterface::class)
              ->give('some_service.two');
}

用法:

$ php artisan tinker
// Aliases
>>> app('some_service.one')
=> App'ImplOne {#669}
>>> app('some_service.two')
=> App'ImplTwo {#671}
// Aliased interface
>>> app('App'SomeInterface')
=> App'ImplOne {#677}
>>> app('App'DependantOne')->dependency
=> App'ImplOne {#677}
// Contextual
>>> app('App'DependantTwo')->dependency
=> App'ImplOne {#676}

在此设置下:

namespace App;
class ImplOne implements SomeInterface {}
class ImplTwo implements SomeInterface {}
class DependantOne
{
    public function __construct(SomeInterface $dependency)
    {
        $this->dependency = $dependency;
    }
}
class DependantTwo
{
    public function __construct(SomeInterface $dependency)
    {
        $this->dependency = $dependency;
    }
}

你的ProfilerService类型的构造函数暗示了一个接口,这意味着你的ProfilerService确实依赖于一个接口。

如果没有任何额外的设置,如果你尝试App::make('App'MyBundle'Services'ProfilerService');,你会得到一个错误,因为Laravel不知道如何解决接口依赖。

当你在你的服务提供程序中执行$this->app->bind('App'MyBundle'Contracts'ProfilerInterface','App'MyBundle'Profiles'SystemProfiler');时,你在告诉Laravel"当你需要解析ProfilerInterface时,创建一个新的SystemProfiler"。

有了这样的绑定设置,如果你尝试App::make('App'MyBundle'Services'ProfilerService');, Laravel将创建一个新的ProfilerService实例,并在构造函数中注入一个新的SystemProfiler实例。

然而,这并不是您想要的,因为您有三种不同的ProfilerInterface实现。你不希望Laravel总是只注射一种。在这种情况下,您将创建自定义绑定,类似于您在Symfony中所做的。

在你的服务提供中,你的绑定看起来像这样:

$this->app->bind('system_profile_service', function($app) {
    return $app->make('App'MyBundle'Services'ProfilerService', [$app->make('App'MyBundle'Profiles'SystemProfiler')]);
});
$this->app->bind('survey_profile_service', function($app) {
    return $app->make('App'MyBundle'Services'ProfilerService', [$app->make('App'MyBundle'Profiles'SurveyProfiler')]);
});
$this->app->bind('offer_profile_service', function($app) {
    return $app->make('App'MyBundle'Services'ProfilerService', [$app->make('App'MyBundle'Profiles'OfferProfiler')]);
});

现在,设置了这些绑定后,无论何时需要,都可以从IOC解析自定义绑定。

$systemProfiler = App::make('system_profiler_service');
$surveyProfiler = App::make('survey_profile_service');
$offerProfiler = App::make('offer_profile_service');