ThinkPHP6开始框架全新重构,以容器的方式来管理所有需要用到的类库。我理解的容器概念如下:
容器内有两个数组
容器使用$provider得到$container是框架最底层的操作,它最先执行
// 用代码简单示意一下<?phpClass Container{public $provider = ['think\exception\Handle' => think\exception\Handle::class,];public $container = [];public function __constract(){foreach($provider as $flag=>$prov){$this->container[$flag] = 得到类单例方法($prov)}}}
服务和门面要一起来解释
先理解三个概念名词:
服务具体实现者服务提供者服务门面一样,是一种把服务具体实现者,注入到容器中的一种方式。服务门面服务提供者一样,是一种把服务具体实现者,注入到容器中的一种方式。服务提供者和服务门面的相同点服务提供者和服务门面都是ThinkPHP6框架提供修改容器中两个数组$provider和$container的方式服务提供者和服务门面的区别服务提供者服务门面ThinkPHP6实现服务提供者的两种方式/app/provider.php,直接定义容器中$provider数组需要array_merge的数组内容在Laytp框架中,默认的/app/provider.php文件内容如下:
<?phpuse app\exception\Http;// 容器Provider定义文件return ['think\exception\Handle' => Http::class,];
当/app/provider.php为空时,其实在ThinkPHP6的容器类的$provider数组中,已经有值'think\exception\Handle' => think\exception\Handle::class,当框架出现异常时,会使用默认的异常接管类进行异常处理,而当/app/provider.php有值时,容器在得到容器中$container数组之前会先将容器中的$provider数组与/app/provider.php文件中的数组进行合并后,再初始化$container数组的值,这样就达到了外部修改容器中类单例的效果
服务提供者类,并继承框架提供的Service基类,且实现register方法下面是官方文档中FileSystemService的代码内容
<?phpnamespace app\service;use my\util\FileSystem;class FileSystemService extends Service{public function register(){$this->app->bind('file_system', FileSystem::class);}}
ThinkPHP6实现服务门面ThinkPHP6中以服务门面的方式修改容器中的类单例,仅一种方式。就是定义门面类并继承Facade基类,以及在门面类中实现getFacadeClass方法,下面是官方举例的Test门面类代码
<?phpnamespace app\facade;use think\Facade;class Test extends Facade{protected static function getFacadeClass(){return 'app\common\Test';}}
服务提供者和服务门面如何选择在Laytp中,没有用服务提供者,服务全部使用服务门面的方式将服务具体实现者注入进了容器。
因为,我们现在使用ThinkPHP6,基本还是会使用php-fpm来运行程序。容器的初始化是每次请求都会执行的,使用服务提供者的方式来将服务具体实现者注入进容器,意味着,每次请求都会实例化所有服务类并注册进容器。服务越多,初始化消耗越大
Laytp中,/app/service/目录下存放了所有的服务具体实现者和对应的服务门面。
服务具体实现者没有文件后缀名。
服务门面的文件后缀名是ServiceFacade。
预留了Service这个后缀给想要使用服务提供者的同学们。
服务提供者呢?如果你使用think-swoole来运行ThinkPHP6程序,应该使用服务提供者的方式,因为使用swoole来运行PHP程序时,Web服务启动后,容器中的单例会一直存在于内存中,不会每次请求都初始化。
特别喜欢使用函数参数进行类的依赖注入写法的同学。服务提供者注入服务具体实现者到容器,才能在方法的参数位置直接依赖注入服务提供者来调用服务具体实现者的方法