架构 —— 服务容器

在一个服务提供者中,能够经过$this->app变量访问容器,而后使用bind方法注册一个绑定,该方法须要两个参数,第一个参数是咱们想要注册的类名或接口名称,第二个参数是返回类的实例的闭包:php

$this->app->bind('HelpSpot\API', function ($app) {    return new HelpSpot\API($app['HttpClient']);
});

注意到咱们接受容器自己做为解析器的一个参数,而后咱们可使用该容器来解析咱们正在构建的对象的子依赖。html

绑定一个单例laravel

singleton方法绑定一个只须要解析一次的类或接口到容器,而后接下来对容器的调用将会返回同一个实例:数组

$this->app->singleton('FooBar', function ($app) {    return new FooBar($app['SomethingElse']);
});

绑定实例闭包

你还可使用instance方法绑定一个已存在的对象实例到容器,随后对容器的调用将老是返回给定的实例:app

$fooBar = new FooBar(new SomethingElse);$this->app->instance('FooBar', $fooBar);

2.1 绑定接口到实现

服务容器的一个很是强大的特性是其绑定接口到实现的能力。咱们假设有一个EventPusher接口及其RedisEventPusher实现,编写完该接口的RedisEventPusher实现后,就能够将其注册到服务容器:函数

$this->app->bind('App\Contracts\EventPusher', 'App\Services\RedisEventPusher');

这段代码告诉容器当一个类须要EventPusher的实现时将会注入RedisEventPusher,如今咱们能够在构造器或者任何其它经过服务容器注入依赖的地方进行EventPusher接口的类型提示:post

use App\Contracts\EventPusher;/**
 * 建立一个新的类实例
 *
 * @param  EventPusher  $pusher
 * @return void
 */public function __construct(EventPusher $pusher){    $this->pusher = $pusher;
}

2.2 上下文绑定

有时侯咱们可能有两个类使用同一个接口,但咱们但愿在每一个类中注入不一样实现,例如,当系统接到一个新的订单的时候,咱们想要经过PubNub而不是Pusher发送一个事件。Laravel定义了一个简单、平滑的方式来定义这种行为:this

$this->app->when('App\Handlers\Commands\CreateOrderHandler')
          ->needs('App\Contracts\EventPusher')
          ->give('App\Services\PubNubEventPusher');

你甚至还能够传递一个闭包到give方法:spa

$this->app->when('App\Handlers\Commands\CreateOrderHandler')
          ->needs('App\Contracts\EventPusher')
          ->give(function () {                  // Resolve dependency...
              });

2.3 标签

少数状况下咱们须要解析特定分类下的全部绑定,好比,也许你正在构建一个接收多个不一样Report接口实现的报告聚合器,在注册完Report实现以后,能够经过tag方法给它们分配一个标签:

$this->app->bind('SpeedReport', function () {    //});$this->app->bind('MemoryReport', function () {    //});$this->app->tag(['SpeedReport', 'MemoryReport'], 'reports');

这些服务被打上标签后,能够经过tagged方法来轻松解析它们:

$this->app->bind('ReportAggregator', function ($app) {    return new ReportAggregator($app->tagged('reports'));
});

三、解析

有不少方式能够从容器中解析对象,首先,你可使用make方法,该方法接收你想要解析的类名或接口名做为参数:

$fooBar = $this->app->make('FooBar');

其次,你能够以数组方式访问容器,由于其实现了PHP的ArrayAccess接口:

$fooBar = $this->app['FooBar'];

最后,也是最经常使用的,你能够简单的经过在类的构造函数中对依赖进行类型提示来从容器中解析对象,包括控制器事件监听器队列任务中间件等都是经过这种方式。在实践中,这是大多数对象从容器中解析的方式。

容器会自动为其解析类注入依赖,好比,你能够在控制器的构造函数中为应用定义的仓库进行类型提示,该仓库会自动解析并注入该类:

<?phpnamespace App\Http\Controllers;use Illuminate\Routing\Controller;use App\Users\Repository as UserRepository;class UserController extends Controller{    /**
     * 用户仓库实例
     */
    protected $users;    /**
     * 建立一个控制器实例
     *
     * @param  UserRepository  $users
     * @return void
     */
    public function __construct(UserRepository $users)
    {        $this->users = $users;
    }    /**
     * 经过指定ID显示用户
     *
     * @param  int  $id
     * @return Response
     */
    public function show($id)
    {        //
    }
}

四、容器事件

服务容器在每一次解析对象时都会触发一个事件,可使用resolving方法监听该事件:

$this->app->resolving(function ($object, $app) {    // 容器解析全部类型对象时调用});$this->app->resolving(function (FooBar $fooBar, $app) {    // 容器解析“FooBar”对象时调用});

正如你所看到的,被解析的对象将会传递给回调,从而容许你在对象被传递给消费者以前为其设置额外属性。

相关文章
相关标签/搜索