• 技术文章 >php框架 >ThinkPHP

    ThinkPHP容器之容器是如何返回实例的

    咔咔咔咔2020-10-12 13:59:15原创64

    在之前的文章中我们简单的梳理了一下容器类,接下来就是对其中一个细节进行深度分析。

    Container实例调用make方法

    本文没有太多文字解析,都在代码注释中说明了执行过程。

    代码static::getInstance()返回了Container的实例后,就会去调用本类的make方法,接下来就是对make方法进行详解了。

    在开始阅读make方法里边的源码之前,我们需要先对几个属性进行简单的梳理一下。

    这四个属性一定要有点印象,并且一定要区别instance和instances。

    这俩个属性一个是单例模式返回当前类的实例,一个是容器中的所有的实例。

    第一次执行结果

       /**
    * 创建类的实例
    * @access public
    * @param string $abstract 类名或者标识
    * @param array|true $vars 变量
    * @param bool $newInstance 是否每次创建新的实例
    * @return object
    */

    public function make($abstract, $vars = [], $newInstance = false)
    {
    // 判断$vars这个变量是否为true
    if (true === $vars) {
    // 总是创建新的实例化对象
    $newInstance = true;
    $vars = [];
    }

    // app 这里就是在容器别名里获取传递过来的app 如果没有则就是app
    $abstract = isset($this->name[$abstract]) ? $this->name[$abstract] : $abstract;

    // 从容器实例中获取 如果存在则直接返回对应的实例 也就是使用注册树模式
    if (isset($this->instances[$abstract]) && !$newInstance) {
    return $this->instances[$abstract];
    }

    // think\App 从容器标识中获取
    if (isset($this->bind[$abstract])) {
    // 将think\App 复制给$concrete变量
    $concrete = $this->bind[$abstract];
    // 用于代表匿名函数的类 判断是不是闭包
    if ($concrete instanceof Closure) {
    $object = $this->invokeFunction($concrete, $vars);
    } else {
    // $this->name['app'] = think\App
    $this->name[$abstract] = $concrete;
    // 在执行一次本类的make方法,也就是本方法
    return $this->make($concrete, $vars, $newInstance);
    }
    } else {
    $object = $this->invokeClass($abstract, $vars);
    }

    if (!$newInstance) {
    $this->instances[$abstract] = $object;
    }

    return $object;
    }

    这是第二次执行流程

        public function make($abstract, $vars = [], $newInstance = false)
    {
    // 判断$vars这个变量是否为true
    if (true === $vars) {
    // 总是创建新的实例化对象
    $newInstance = true;
    $vars = [];
    }

    // app 这里就是在容器别名里获取传递过来的app 如果没有则就是app
    // 第二次执行时 $abstract = think\App
    $abstract = isset($this->name[$abstract]) ? $this->name[$abstract] : $abstract;

    // 从容器实例中获取 如果存在则直接返回对应的实例 也就是使用注册树模式
    if (isset($this->instances[$abstract]) && !$newInstance) {
    return $this->instances[$abstract];
    }

    // think\App 从容器标识中获取
    // 第二次执行$this->bind['think\App']不存在走else
    if (isset($this->bind[$abstract])) {
    // 将think\App 复制给$concrete变量
    $concrete = $this->bind[$abstract];
    // 用于代表匿名函数的类 判断是不是闭包
    if ($concrete instanceof Closure) {
    $object = $this->invokeFunction($concrete, $vars);
    } else {
    // $this->name['app'] = think\App
    $this->name[$abstract] = $concrete;
    // 在执行一次本类的make方法,也就是本方法
    // think\App
    return $this->make($concrete, $vars, $newInstance);
    }
    } else {
    // think\App
    $object = $this->invokeClass($abstract, $vars);
    }

    if (!$newInstance) {
    // 把创建的容器存起来
    //$this->instances['think\App'] = $object;
    $this->instances[$abstract] = $object;
    }

    return $object;
    }
    public function invokeClass($class, $vars = [])
    {
    try {

    /**
    * ReflectionClass Object
    (
    [name] => think\App
    )
    */

    // 这里就是之前文章提到的反射
    $reflect = new ReflectionClass($class);


    if ($reflect->hasMethod('__make')) {
    $method = new ReflectionMethod($class, '__make');

    if ($method->isPublic() && $method->isStatic()) {
    $args = $this->bindParams($method, $vars);
    return $method->invokeArgs(null, $args);
    }
    }
    // 通过反射获取think\App的构造函数
    $constructor = $reflect->getConstructor();

    $args = $constructor ? $this->bindParams($constructor, $vars) : [];
    // 从给出的参数创建一个新的类实例
    return $reflect->newInstanceArgs($args);

    } catch (ReflectionException $e) {
    throw new ClassNotFoundException('class not exists: ' . $class, $class);
    }
    }

    执行流程图

    既然把代码都理清楚了,这时来理一下执行的流程图可以看的更清晰。

    坚持学习、坚持写博、坚持分享是咔咔从业以来一直所秉持的信念。希望在偌大互联网中咔咔的文章能带给你一丝丝帮助。我是咔咔,下期见。

    以上就是ThinkPHP容器之容器是如何返回实例的的详细内容,更多请关注php中文网其它相关文章!

    本文原创发布php中文网,转载请注明出处,感谢您的尊重!
    专题推荐:ThinkPHP
    上一篇:ThinkPHP容器之初步解析 下一篇:ThinkPHP容器之反射的运用
    第13期线上培训班

    相关文章推荐

    • ThinkPHP之玩转自己的容器类• ThinkPHP容器之Countable巧用• ThinkPHP容器之你不知道的count用法• ThinkPHP容器之初步解析

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网