一、container容器类分析
Countable巧用
Container容器类文件是在thinkphp\library\think目录下的,我认为它是框架的一个精华,它可能很不便的治理框架的类,不便咱们应用。
在Container中,它用到了很多类,还有反射机制,所以反射机制是须要咱们去理解的一个货色。其中Countable是php内置的一个类,接下来咱们进行对它的演示。
首先在extend目录下创立一个TestCountable类,而后它继承Countable,因为是继承的Countable,须要把其中的count办法定义进去,不然会报错,而后在count外面轻易返回内容。接着在控制器index.php中创立办法去调用这个类,然而它的调用和其余的有点区别,惯例调用是这样的,$obj=new TestCountable(); $a = $obj->count();
而Countable是这样的$obj = new TestCountable(); $a = count($obj);
。这就是它的区别。
获取容器内的实例剖析
$this->instance
获取容器对象实例$this->bind
容器绑定标识$this->name
容器标识别名
[APP] => think\App
[log] => think\Log
相似于容器绑定标识的内容$this->instances
容器中的对象的实例
[think\App] => think\App Object
[think\Config] => think\Config Object等等。
那么咱们如何去学习容器呢,咱们还是联合框架代码来进行剖析。
首先咱们定位到入口文件index.php
这里它用了Container的get办法,并传入了一个app参数,咱们来看一下get办法的逻辑。
get办法是获取容器中的对象实例。这里它传入了三个参数,三个参数各是什么意思,正文下面有,传入的app对应的就是think\App,而后它用了单例模式,getInstance就是一个单例,而后调用make办法。
首先会对$vars进行判断,如果是true,就把它置空,让$newInstace为true。接下来进行判断$this->name[$abstract],因为传入参数是app,$abstract => app。而后判断$abstract有没有实例,默认是没有的,就返回一个实例。而后接着就是容器绑定标识,$concrete对应的就是think\App。接着如果它是闭包的话,就会走到invokeFunction,如果不是,就设置容器标识别名,相当于$this->name[“app”] = think\App 。而后再去调用make办法,这个时候,传的参数就不一样了,第一个参数就成为think\App,这个时候两个isset都是没有的,就不会走这两个逻辑。间接跳到invokeClass办法,这个时候会返回一个对象。而后把这个对象放入容器中的对象实例,最初返回这个对象。
invokeClass办法
当初咱们讲一下invokeClass办法,这个办法传入了两个参数,第一是类名,第二是它的参数。而后实例化反射类ReflectionClass,而后判断这个类外面是否有__make办法,如果有的话就获取到这个类,接着判断这个类的属性是不是public或者static,如果是的,就进行实例化,而后返回。而__make办法在Config类里是存在的,所以这里实例化的是一个Config类。
容器类的应用场景
容器类能够这样应用,这种是应用的Facade门面的办法来应用的。
第二种能够这样应用,相似入口文件那样。这两种都能打印出app的config配置。
咱们还有另外一种应用场景的,这种场景咱们应用到了php的助手函数,在helper.php中的app办法中。
咱们能够这样用,间接app("config);
,这样能够间接拿到配置。
二、Facade门面模式
门面为容器中的类提供了一个动态调用接口,相比于传统的静态方法调用,带来了更好的可测试性和扩展性。接下来还是通过代码来理解。
在thinkphp\library\think目录下有一个Facade文件,它相当于门面的一个父类,子类在think\facade目录下,外面有许多的类,它们都须要继承Facade父类。这些子类中都只有一个办法,getFacadeClass办法,外面逻辑就是返回绑定的标识。它的作用是在Facade外面体现的。
这里获取到这个标识,而后判断有没有这个标识,如果有就返回这个实例,如果没有,就绑定到标识中去。
咱们接下来通过演示来剖析一下Facade代码。
咱们在index控制器外面创立一个facade办法,而后打印Config::get("app");
,它是怎么走的呢,它会找到think\facade\Config.php这个文件,然而在这个文件外面是没有get办法的,而且在它的父类Facade外面也没有get办法,那么它是怎么执行的呢。因为Facade外面没有get办法,那么它会走到__callStatic办法,而后去创立一个get办法。接下来咱们来具体解说一下__callStatic办法。咱们创立一个Test类,在Test类外面增加__callStatic办法,而后打印一下传入的参数,在应用层index.php去调用一下这个类,代码如下:
咱们调用的abcd办法在Test外面是不存在的,咱们看一下打印的参数是什么。
咱们持续看Facade类的__callStatic办法,
在这里会执行createFacade办法,这个办法咱们在下面解释过了,所以最终会把get放入$this->[name]
标识外面去。最终返回的是一个实例。
联合下面的形容,facade办法就是依据容器外面是否有静态方法get,如果有调用,如果没有就进行实例化,进行调用。
Facade图例
Facade实战
Facade有两个应用场景,第一个:
咱们在app目录下创立common和facade文件夹,而后别离在两个目录下创立Test文件,common下的Test外面创立test办法,并输入内容。facade目录下须要继承Facade门面类,而后调用getFacadeClass办法,而后返回common下Test的门路,而后在应用层去调用appfacadeTest::test();
第二种:
facade目录下的Test文件不再写办法,而后在控制器外面这样应用。Facade::bind('app\facade\Test','app\common\Test'); app\facade\Test::test();