详解如何实现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);
内容版权声明:除非注明,否则皆为本站原创文章。
