ThinkPHP6框架全新重构,以容器的方式来管理所有需要用到的类库。我理解的容器概念如下:
容器内有两个数组
容器使用$provider得到$container是框架最底层的操作,它最先执行
// 用代码简单示意一下
<?php
Class 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
文件内容如下:
<?php
use 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
的代码内容
<?php
namespace 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门面类代码
<?php
namespace 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服务启动后,容器中的单例会一直存在于内存中,不会每次请求都初始化。
特别喜欢使用函数参数进行类的依赖注入写法的同学。服务提供者
注入服务具体实现者
到容器,才能在方法的参数位置直接依赖注入服务提供者
来调用服务具体实现者
的方法