博客列表 >tp中的app()助手函数是如何获取对象的?

tp中的app()助手函数是如何获取对象的?

有什么是忘不了的的博客
有什么是忘不了的的博客原创
2020年07月14日 10:37:331449浏览

tp给我们提供啦一个容器的概念,用来储存我们生产的类实例。在下次需要使用类实例时可以快速获取。

那app()助手函数是如何工作的:    

    通过查看助手文件得到他其实调用的是:Container::get()方法。

    function app($name = 'think\App', $args = [], $newInstance = false)
    {
        return Container::get($name, $args, $newInstance);
    }

    我们在去看Container::get()方法。

    public static function get($abstract, $vars = [], $newInstance = false)
    {
        //通过getInstance方法创建一个当前容器的实例(单例模式)再去调用make()方法
        return static::getInstance()->make($abstract, $vars, $newInstance);
    }

    我们来看make()方法:这个方法很重要,门面其实也是通过这个方法来创建对象。

    public function make($abstract, $vars = [], $newInstance = false)
    {
        if (true === $vars) {
            // 总是创建新的实例化对象
            $newInstance = true;
            $vars        = [];
        }
        static $i = 0;
        $abstract = isset($this->name[$abstract]) ? $this->name[$abstract] : $abstract;
        //通过容器获取类的对象
        if (isset($this->instances[$abstract]) && !$newInstance) {
//            echo '容器中'.$i++.'<br>';
            return $this->instances[$abstract];
        }
            //通过反射创建类的对象
        if (isset($this->bind[$abstract])) {
            $concrete = $this->bind[$abstract];
            if ($concrete instanceof Closure) {
                $object = $this->invokeFunction($concrete, $vars);
                echo '反射'.$i++.PHP_EOL;
            } else {
                $this->name[$abstract] = $concrete;
                return $this->make($concrete, $vars, $newInstance);
            }
        } else {
            echo '反射'.$i++.PHP_EOL;
            $object = $this->invokeClass($abstract, $vars);
        }

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

        return $object;
    }

我为了证明app()在调用的时候是通过容器来获取对象的还是通过反射来获取对象的,在这个类中定义了一个:static $i = 0;和echo '反射'.$i++.PHP_EOL;来输出调用的方法和次数。方便观察。

当我的方法为空时:

(TPBSPE)VGJ`MBK4ZH[IGL9.png

输出为:

W8({%TRHB`02[UC@WN0TT$C.png

为什么会使出  17次的放射呢?

因为在框架初始化的时候会来获取一些默认的类对象(大概是这个意思)。所以这前17次输出都和我们没有关系

现在我在方法里调用一次我自己定义的一个类文件。

J6GWX4O3}X$O7W3HYK2ZIL3.png

再看输出

50T]]L@V{OB5V_25(%IS)EG.png

这是输出多啦一次 ‘反射’这说明当我们通过app()来获取一个我们未向容器注册过的类的时候,他会通过我们提供的命名空间,用反射来创建这个类的对象。

当我们调用两次app()来获取相同的类对象时:

    public function lize(){
//        bind('Redis',new \Redis);
        $redis = app('Redis');
        $redis = app('Redis');
    }

再看输出:

50T]]L@V{OB5V_25(%IS)EG.png并没有多输出一次‘反射’,这说明我们第二次调用的时候并没有通过反射来获取类对象。而是做的容器。

总结:

    当我们通过app()来获取一个类对象时,先会在容器里获取,获取不到去通过反射来获取。反射获取对象成功后,在吧这个对象放到容器里。下次获取的时候直接去容器里获取。(去不去容器里获取还可以通过,app()的第二个参数来决定,当为true时就不会走容器,不管容器里有没有。)








声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议