### 2018 年 11 月 5 日 发布 ## 介绍 `5.2`版本的第一个`Beta1`测试版本发布,仅供学习和测试用途,暂时请不要用于实际项目。 >[danger] `5.2`的目标致力于提供一个更简洁、更标准的核心框架,对于一些非必须功能力求组件化或者通过扩展解决。 目前已经完成的主要特性包括: * 基于PHP`7.1+`重构; * 强类型严格约束; * 完全依赖`composer`; * 原生多应用支持; * 支持应用的`Composer`引入; * 引入事件系统; * 增加`PSR-6`和`PSR-16`支持; 目前核心功能基于PHP`7.1`实现,未来的升级版本不排除要求PHP`7.2+`的可能性。 ## 安装 ~~~ composer create-project topthink/think tp5 5.2.*-dev ~~~ 启动服务 ~~~ cd tp5 php think run ~~~ 然后就可以在浏览器中访问 ~~~ http://localhost:8000 ~~~ 如果需要更新框架使用 ~~~ composer update topthink/framework ~~~ ## 目录结构 >[info] 相对于`5.1`来说,`5.2`版本目录结构的变化不大,主要是默认应用目录改为`app`,`thinkphp`目录不再放置根目录而是直接安装到`vendor`目录下。 ~~~cmd www WEB部署目录(或者子目录) ├─app 应用目录 │ ├─command.php 命令行定义文件 │ ├─common.php 公共函数文件 │ ├─event.php 事件定义文件 │ ├─controller 控制器目录 │ ├─model 模型目录 │ ├─view 视图目录 │ └─ ... 更多类库目录 ├─config 应用配置目录 ├─route 路由定义目录 ├─public WEB目录(对外访问目录) │ ├─index.php 入口文件 │ ├─router.php 快速测试文件 │ └─.htaccess 用于apache的重写 ├─extend 扩展类库目录 ├─runtime 应用的运行时目录 ├─vendor 第三方类库目录(Composer依赖库) ├─composer.json composer 定义文件 ├─LICENSE.txt 授权说明文件 ├─README.md README 文件 ├─think 命令行入口文件 ~~~ >[danger] 该目录结构只是默认生成的(单应用模式),具体会因为你是否采用多应用模式而存在差异。 ## 入口文件 由于`5.2`版本完全依赖`Composer`,取消了原本的`think\Loader`类,因此入口文件的写法有所调整。 系统安装后提供了一个默认的入口文件(位于`public/index.php`),内容如下: ``` // [ 应用入口文件 ] namespace think; require __DIR__ . '/../vendor/autoload.php'; // 执行应用并响应 (new App())->run()->send(); ``` 如果`app`目录下面直接是`controller`、`model`以及`view`等类库目录,则为单应用模式(默认模式),如果在`app`目录下创建了应用子目录,则自动变成多应用模式。 单应用和多应用的目录结构区别如下(主要在`app`目录): 单应用 ``` ├─app 应用目录 │ ├─controller 控制器目录 │ ├─model 模型目录 │ ├─view 视图目录 │ └─ ... 更多类库目录 ├─public WEB目录(对外访问目录) │ ├─index.php 入口文件 ├─config 应用配置目录 ├─route 路由定义目录 ├─runtime 应用的运行时目录 ``` 多应用 ``` ├─app 应用目录 │ ├─index 主应用 │ │ ├─controller 控制器目录 │ │ ├─model 模型目录 │ │ ├─view 视图目录 │ │ ├─config 配置目录(优先) │ │ └─ ... 更多类库目录 │ ├─app2 应用2 │ │ ├─controller 控制器目录 │ │ ├─model 模型目录 │ │ ├─view 视图目录 │ │ ├─config 配置目录(优先) │ │ └─ ... 更多类库目录 ├─public WEB目录(对外访问目录) │ ├─index.php 主入口文件 │ ├─app2.php 入口文件2 ├─config 应用配置目录 │ ├─index index应用配置 │ └─app2 app2应用配置 ├─route 路由定义目录 │ ├─index index应用路由定义目录 │ └─app2 app2应用路由定义目录 ├─runtime 应用的运行时目录 │ ├─index index应用运行时目录 │ └─app2 app2应用运行时目录 ``` 从目录结构可以看出来,每个应用相对保持独立,并且每个应用都有一个对应的入口文件,应用下面还可以通过多级控制器来维护控制器分组。 通过URL重写可以实现在一个统一的入口文件访问不同的应用。 新版的`think\App`类的定制性更灵活,你可以在入口文件中对应用进行定制。 ``` // [ 应用入口文件 ] namespace think; require __DIR__ . '/../vendor/autoload.php'; // 实例化应用 $app = new App(); // 设置当前应用的路径 $app->path('path/to/name'); // 开发调试模式 $app->debug(true); // 设置应用名称 $app->name('name'); // 设置应用的命名空间 $app->setNamespace('app\name'); // 开启应用类库后缀 $app->suffix(true); // 绑定当前应用的请求对象 $app->bind('request', $request); // 执行应用并输出响应 $app->run()->send(); ``` 如果你的某个应用来自于`composer`库,只需要在入口文件中指定应用的命名空间。 ## 命令行 如果采用了多应用模式,命令行可以支持生成不同应用的类文件 ``` php think make:controller index@User php think make:model app2@Blog ``` ## Db类和模型 `Db`类也采用了`Facade`机制,所以你在使用`Db`类查询的时候,应该使用: ``` use think\facade\Db; ... Db::name('user')->find(); ``` 模型的用法目前基本上变化不大。 ## 事件机制 事件机制用于替代5.1版本的`Hook`和行为,可以通过命令行生成事件类。 ``` php think make:event index@User ``` ``` namespace app\index\event; class UserLogin { } ``` 生成监听器 ``` php think make:listener index@UserLogin ``` ``` namespace app\index\listener; class UserLogin { public function handle($event) { // 事件监听处理 } } ``` 给事件绑定别名 ``` Event::bind('UserLogin', '\app\index\event\UserLogin'); ``` 使用监听器 ``` Event::listen('UserLogin', '\app\index\listener\UserLogin'); ``` 或者手动注册事件监听 ``` use think\facade\Event; Event::listen('UserLogin', function(){ }); ``` 生成事件订阅类 ``` php think make:subscribe index@User ``` ``` namespace app\index\subscribe; class User { public function onUserLogin($event) { // 事件响应处理 } } ``` 注册事件订阅者 ``` Event::subscribe('\app\index\subscribe\User'); ``` 上面的相关操作可以通过在应用目录的`event.php`文件中直接配置,而无需手动操作。 ``` return [ 'bind' => [ 'UserLogin' => ['\app\index\event\UserLogin'], // 更多事件别名定义 ], 'listen' => [ 'UserLogin' => ['\app\index\listener\UserLogin'], // 更多事件监听 ], 'subscribe' => [ '\app\index\subscribe\User', // 更多事件订阅 ], ]; ``` 内置已经绑定别名的事件包括`AppInit`、`AppBegin`、`ActionBegin`、`AppEnd`等,也就是说原来的`Hook`钩子已经全部改造为事件类。 ## 废弃用法 * 模块概念(应用下不再有模块的概念,用多级控制器替代); * Hook和行为系统(使用事件系统替代); * 路由的数组返回定义(统一使用方法定义路由); * Session的前缀机制(已经被简化); * Config的`range`机制(已经被简化); * 核心`Facade`类的别名(避免混淆而废弃);