详解如何实现Laravel的服务容器的方法示例(4)
6. 自定义依赖参数
现在有个问题,如果类依赖的参数不是类或接口,只是一个普通变量,这时候就无法从容器中获取依赖参数了,也就无法实例化类了。
那么接下来我们就支持一个新功能,在调用make方法时,支持传第二个参数$parameters,这是一个数组,无法从容器中获取的依赖,就从这个数组中找。
当然,make方法是用不到这个参数的,因为它不负责实例化类,它直接传给build方法。在build方法寻找依赖的参数时,就先从$parameters中找。这样就实现了自定义依赖参数。
需要注意的一点是,build方法是按照参数的名字来找依赖的,所以parameters中的键名也必须跟__construct中参数名一致。
class ParametersContainer extends InjectionContainer
{
// 获取服务
public function make($name, array $parameters = [])
{
if (isset($this->instances[$name])) {
return $this->instances[$name];
}
if (isset($this->bindings[$name])) {
// 执行回调函数并返回
$instance = call_user_func($this->bindings[$name]['callback']);
if ($this->bindings[$name]['shared']) {
// 标记为单例时,存储到服务中
$this->instances[$name] = $instance;
}
} else {
// 使用build方法构建此类
$instance = $this->build($name, $parameters);
}
return $instance;
}
// 构建一个类,并自动注入服务
public function build($class, array $parameters = [])
{
$reflector = new ReflectionClass($class);
$constructor = $reflector->getConstructor();
if (is_null($constructor)) {
// 没有构造函数,直接new
return new $class();
}
$dependencies = [];
// 获取构造函数所需的参数
foreach ($constructor->getParameters() as $dependency) {
if (isset($parameters[$dependency->getName()])) {
// 先从自定义参数中查找
$dependencies[] = $parameters[$dependency->getName()];
continue;
}
if (is_null($dependency->getClass())) {
// 参数类型不是类或接口时,无法从容器中获取依赖
if ($dependency->isDefaultValueAvailable()) {
// 查找默认值,如果有就使用默认值
$dependencies[] = $dependency->getDefaultValue();
} else {
// 无法提供类所依赖的参数
throw new Exception('找不到依赖参数:' . $dependency->getName());
}
} else {
// 参数类型是类时,就用make方法构建该类
$dependencies[] = $this->make($dependency->getClass()->name);
}
}
return $reflector->newInstanceArgs($dependencies);
}
}
// ----------- ↓↓↓↓示例代码↓↓↓↓ ----------- //
class Redis
{
}
class Cache
{
protected $redis;
protected $name;
protected $default;
// 构造函数中依赖Redis服务和name参数,name的类型不是类,无法从容器中查找
public function __construct(Redis $redis, $name, $default = '默认值')
{
$this->redis = $redis;
$this->name = $name;
$this->default = $default;
}
}
$container = new ParametersContainer();
// 绑定Redis服务
$container->singleton(Redis::class, function () {
return new Redis();
});
// 构建Cache类
$cache = $container->make(Cache::class, ['name' => 'test']);
var_dump($cache);
内容版权声明:除非注明,否则皆为本站原创文章。
