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