laravel学习之IOC容器分析(二)
在laravel学习之IOC容器分析(一)中,曾经提到过在
$this->registerBaseServiceProviders();
if ($this->booted) { $this->bootProvider($provider); }
boorProvider()里面有用call方法来解决服务提供器的依赖问题,那我们就来研究一下这个call()方法
protected function bootProvider(ServiceProvider $provider) { if (method_exists($provider, 'boot')) { return $this->call([$provider, 'boot']); } }
先判断这个服务提供器里面是否有boot这个方法,有的话调用就调用call方法。
/** * Call the given Closure / class@method and inject its dependencies. * * @param callable|string $callback * @param array $parameters * @param string|null $defaultMethod * @return mixed */ public function call($callback, array $parameters = [], $defaultMethod = null) { if ($this->isCallableWithAtSign($callback) || $defaultMethod) { return $this->callClass($callback, $parameters, $defaultMethod); } $dependencies = $this->getMethodDependencies($callback, $parameters); return call_user_func_array($callback, $dependencies); }
如果调用这个方法时传的值是这样的话call(ASeverProvider@a)的话,就会调用callClass方法
protected function callClass($target, array $parameters = [], $defaultMethod = null) { $segments = explode('@', $target); // If the listener has an @ sign, we will assume it is being used to delimit // the class name from the handle method name. This allows for handlers // to run multiple handler methods in a single class for convenience. $method = count($segments) == 2 ? $segments[1] : $defaultMethod; if (is_null($method)) { throw new InvalidArgumentException('Method not provided.'); } return $this->call([$this->make($segments[0]), $method], $parameters); }
把这个字符串拆分,判断是否有2个元素,有的话就把$method这个变量设为要调用的方法名,把第一个参数$segments[0]即例子中的ASeverProvider当作类名,然后再次调用call方法。
然后就来到了
protected function getMethodDependencies($callback, array $parameters = []) { $dependencies = []; foreach ($this->getCallReflector($callback)->getParameters() as $parameter) { $this->addDependencyForCallParameter($parameter, $parameters, $dependencies); } return array_merge($dependencies, $parameters); }
里面调用了getCallReflector
protected function getCallReflector($callback) { if (is_string($callback) && strpos($callback, '::') !== false) { $callback = explode('::', $callback); } if (is_array($callback)) { return new ReflectionMethod($callback[0], $callback[1]); } return new ReflectionFunction($callback); }
这里就是call方法解决依赖的根本了,这个方法运用了ReflectionMethod,这个是依靠php的反射机制实现的,所以
$this->getCallReflector($callback)->getParameters()
就是获取当前类boot方法的参数,也就是依赖注入的方法注入,然后就在下面添加到$dependencies数组中,然后就通过
call_user_func_array($callback, $dependencies)
放进当前类的boot方法中。
执行完后返回$provider,整过过程就是这样。
完....