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,整过过程就是这样。

  完....

 

posted @ 2017-05-15 21:34  Gikkson  阅读(262)  评论(0编辑  收藏  举报