laravel学习(三)-服务容器

Service Container

Posted by zwtisme on June 6, 2018

介绍laravel框架中服务容器的主要使用方法。

文档

英文文档

中文文档

绑定

1.bind

此方法是最常用的服务绑定方法。

函数说明
/**
 * Register a binding with the container.
 * 绑定服务到容器
 * @param  string  $abstract 类别名,实际类名,接口类名
 * @param  \Closure|string|null  $concrete 类的构建闭包,实际类名,null=>$concrete=$abstract
 * @param  bool  $shared 是否为共享服务
 * @return void
 */
function bind($abstract, $concrete = null, $shared = false) {
    
}
典型应用
//类别名绑定到构建闭包
$this->app->bind('cache', function ($app) {
    return new CacheManager($app);
});
//类别名绑定到实际类名
$this->app->bind('cache', 'Illuminate\Cache\CacheManager');
//接口类名绑定到实际类名
$this->app->bind('App\Contracts\EventPusher', 'App\Services\RedisEventPusher');
流程图

image

2.singleton

此方法可将服务绑定为共享服务。

函数说明
/**
 * Register a shared binding in the container.
 * 绑定单例服务到容器
 * @param  string  $abstract 类别名,实际类名,接口类名
 * @param  \Closure|string|null  $concrete 类的构建闭包,实际类名,null=>$concrete=$abstract
 * @return void
 */
function singleton($abstract, $concrete = null) {
    
}
典型应用
//类别名绑定到构建闭包,服务为共享的
$this->app->singleton('cache', function ($app) {
    return new CacheManager($app);
});
流程图

image

3.instance

此方法可将服务的实例直接绑定到容器的共享服务中。

函数说明
/**
 * Register an existing instance as shared in the container.
 * 绑定抽象类型的实例为共享实例
 * @param  string  $abstract 类别名,实际类名,接口类名
 * @param  mixed   $instance 实例
 * @return mixed
 */
function instance($abstract, $instance) {
    
}
典型应用
//类实例化
$api = new HelpSpot\API(new HttpClient);
//实例绑定
$this->app->instance('HelpSpot\API', $api);
流程图

image

4.when

此方法可进行服务的上下文绑定,需要配合ContextualBindingBuilder中的needs与give使用,在解析时使用give代替needs。

函数说明
/**
 * Define a contextual binding.
 * 创建上下文绑定
 * @param  string  $concrete 实际类名
 * @return \Illuminate\Contracts\Container\ContextualBindingBuilder
 */
function when($concrete) {
}

/**
 * Define the abstract target that depends on the context.
 * 上下文依赖的抽象类型
 * @param  string  $abstract 类别名,实际类名,接口类名,变量名
 * @return $this
 */
function needs($abstract) {
    
}

/**
 * Define the implementation for the contextual binding.
 * 抽象类型的实现
 * @param  \Closure|string  $implementation 实现闭包,字符串
 * @return void
 */
function give($implementation) {
    
}
典型应用
//绑定构造函数中简单参数的初始数据,在解析when类的时用到
$this->app->when('App\Http\Controllers\UserController')
          ->needs('$variableName')
          ->give($value);
//绑定构造函数中类参数的实现,在解析when类的依赖类时用到

//如下2个绑定表示,在解析PhotoController::class与VideoController::class时都需要依赖Filesystem::class,但是根据不同的功能,给予了Filesystem::class不同的实现
$this->app->when(PhotoController::class)
          ->needs(Filesystem::class)
          ->give(function () {
              return Storage::disk('local');
          });

$this->app->when(VideoController::class)
          ->needs(Filesystem::class)
          ->give(function () {
              return Storage::disk('s3');
          });
          
流程图

image

5.tag

此方法可将多个服务进行标记,在解析时可以使用tag同时解析多个服务。

函数说明
/**
 * Assign a set of tags to a given binding.
 * 为一组绑定设定标记
 * @param  array|string  $abstracts 抽象类型
 * @param  array|mixed   ...$tags 需要设定的标记
 * @return void
 */
function tag($abstracts, $tags) {
    
}
典型应用
$this->app->bind('SpeedReport', function () {
    //
});

$this->app->bind('MemoryReport', function () {
    //
});

$this->app->tag(['SpeedReport', 'MemoryReport'], 'reports');
流程图

image

6.extend

此方法可对解析后的服务实例添加扩展方法,用于对实例进行装饰处理。

函数说明
/**
 * "Extend" an abstract type in the container.
 * 扩展容器中的服务
 * @param  string    $abstract 抽象类型
 * @param  \Closure  $closure 闭包
 * @return void
 *
 * @throws \InvalidArgumentException
 */
function extend($abstract, Closure $closure) {
    
}
典型应用
//对服务的实例进行装饰处理
$this->app->extend(Service::class, function($service) {
    return new DecoratedService($service);
});
流程图

image

解析

1.make(app)

最常用的从容器中解析实例的方法。

函数说明
/**
 * Resolve the given type from the container.
 * 从服务容器中解析服务
 * (Overriding Container::make)
 * @param  string  $abstract 类别名,实际类名,接口类名
 * @param  array  $parameters 类依赖的参数
 * @return mixed
 */
public function make($abstract, array $parameters = []) {
}
典型应用
$api = $this->app->make('HelpSpot\API');
流程图

image

2.makeWith(container)

在解析类时,可直接传入类的依赖项,而不需要通过容器去解析。

函数说明
/**
 * An alias function name for make().
 * <br>make方法的别名
 * @param  string  $abstract 类别名,实际类名,接口类名
 * @param  array  $parameters 类依赖的参数
 * @return mixed
 */
public function makeWith($abstract, array $parameters = []) {
}
典型应用
$api = $this->app->makeWith('HelpSpot\API', ['id' => 1]);
流程图

image

3.resolve(helpers)

如果访问不到$app,可通过此全局辅助函数解析实例。

函数说明
if (! function_exists('resolve')) {
    /**
     * Resolve a service from the container.
     * 从容器中解析类
     * @param  string  $name 抽象类型
     * @return mixed
     */
    function resolve($name)
    {
        return app($name);
    }
}

if (! function_exists('app')) {
    /**
     * Get the available container instance.
     * 从容器中解析实例
     * @param  string  $abstract 类别名,实际类名,接口类名
     * @param  array   $parameters 类依赖的参数
     * @return mixed|\Illuminate\Foundation\Application
     */
    function app($abstract = null, array $parameters = [])
    {
        if (is_null($abstract)) {
            //如果没有抽象类型,返回容器实例
            return Container::getInstance();
        }
        //解析抽象类型
        return Container::getInstance()->make($abstract, $parameters);
    }
}
典型应用
$api = resolve('HelpSpot\API');
流程图

image

事件

注册解析服务时触发的全局事件或服务的事件,可在服务提供者的boot方法中注册。

public function boot()
{
    $this->app->resolving(function ($object, $app) {
        //注册全局解析方法,解析任何类型时都会触发
    });
    
    $this->app->resolving(HelpSpot\API::class, function ($api, $app) {
        //注册类型解析方法,解析对应类型时才会触发
    });
}

应用的启动在BootProviders中的bootstrap方法里。

public function bootstrap(Application $app)
{
    $app->boot();
}

注释版代码

Application

Container