详解如何实现Laravel的服务容器的方法示例(5)

提示:实际上,Laravel容器的build方法并没有第二个参数$parameters,它是用类属性来维护自定义参数。原理都是一样的,只是实现方式不一样。这里为了方便理解,不引入过多概念。

7. 服务别名

别名可以理解成小名、外号。服务别名就是给已绑定的服务设置一些外号,使我们通过外号也能找到该服务。

这个就比较简单了,我们增加一个新的数组$aliases,用来存储别名。再增加一个方法alias,用来让外部注册别名。

唯一需要我们修改的地方,就是在make时,要先从$aliases中找到真实的服务名。

class AliasContainer extends ParametersContainer
{
  // 服务别名
  protected $aliases = [];

  // 给服务绑定一个别名
  public function alias($alias, $name)
  {
    $this->aliases[$alias] = $name;
  }

  // 获取服务
  public function make($name, array $parameters = [])
  {
    // 先用别名查找真实服务名
    $name = isset($this->aliases[$name]) ? $this->aliases[$name] : $name;

    return parent::make($name, $parameters);
  }
}

// ----------- ↓↓↓↓示例代码↓↓↓↓ ----------- //

$container = new AliasContainer();

// 绑定服务
$container->instance('text', '这是一个字符串');
// 给服务注册别名
$container->alias('string', 'text');
$container->alias('content', 'text');

var_dump($container->make('string'));
var_dump($container->make('content'));

8. 扩展绑定

有时候我们需要给已绑定的服务做一个包装,这时候就用到扩展绑定了。我们先看一个实际的用法,理解它的作用后,才看它是如何实现的。

// 绑定日志服务
$container->singleton('log', new Log());

// 对已绑定的服务再次包装
$container->extend('log', function(Log $log){
  // 返回了一个新服务
  return new RedisLog($log);
});

现在我们看它是如何实现的。增加一个$extenders数组,用来存放扩展器。再增加一个extend方法,用来注册扩展器。

然后在make方法返回$instance之前,按顺序依次调用之前注册的扩展器。

class ExtendContainer extends AliasContainer
{
  // 存放扩展器的数组
  protected $extenders = [];

  // 给服务绑定扩展器
  public function extend($name, $extender)
  {
    if (isset($this->instances[$name])) {
      // 已经实例化的服务,直接调用扩展器
      $this->instances[$name] = $extender($this->instances[$name]);
    } else {
      $this->extenders[$name][] = $extender;
    }
  }

  // 获取服务
  public function make($name, array $parameters = [])
  {
    $instance = parent::make($name, $parameters);

    if (isset($this->extenders[$name])) {
      // 调用扩展器
      foreach ($this->extenders[$name] as $extender) {
        $instance = $extender($instance);
      }
    }

    return $instance;
  }
}

// ----------- ↓↓↓↓示例代码↓↓↓↓ ----------- //

class Redis
{
  public $name;

  public function __construct($name = 'default')
  {
    $this->name = $name;
  }

  public function setName($name)
  {
    $this->name = $name;
  }
}

$container = new ExtendContainer();

// 绑定Redis服务
$container->singleton(Redis::class, function () {
  return new Redis();
});

// 给Redis服务绑定一个扩展器
$container->extend(Redis::class, function (Redis $redis) {
  $redis->setName('扩展器');
  return $redis;
});
$redis = $container->make(Redis::class);
var_dump($redis->name);


      

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/6002.html