5.2
版本目前属于测试版本,存在不稳定性,请勿轻易用于正式项目。
安装及入口文件
安装
由于5.2
版本完全依赖Composer
,因此只能通过composer
安装才能使用,不同于5.0
和5.1
版本,下载或者Git
安装都可以使用。
由于只是测试阶段,所以必须安装dev
版本
1 | composer create-project topthink/think thinkphp52 5.2.*-dev |
启动服务
1 | cd thinkphp52 |
入口文件
新版的入口文件还是位于public
目录下面,由于直接使用composer
的自动加载机制,因此框架核心已经不再使用Loader
类了而是改为加载composer
的autoload
文件。
1 |
|
autoload.php
1 |
|
注意每一个入口文件在新版里面总是对应一个应用,有意思的是,不同的应用入口文件除了文件名不同外代码可能完全一样(会自动绑定到文件名对应的应用)。
如果你的文件名和应用名不一致,那么可能需要略微调整如下:
1 |
|
think\App
类还提供了很多的设置方法,都可以在run
之前调用。这个有兴趣深入了解的可以通过源码查看。
源码: thinkphp52/vendor/topthink/framework/src/think/App.php
App.php
这里展示一些方法和作用, 源码自己去看
1 |
|
由于新版本一个入口文件对应一个应用,如果你希望保持5.1
版本的URL形式不变,直接访问不同的应用,一个最简单的办法就是设置Apache
的.htaccess
文件。
1 | <IfModule mod_rewrite.c> |
应用目录及命名空间调整
新版的目录结构其实看起来和5.1
并无多大的差异,除了thinkphp
框架目录已经纳入vendor
之外。另外应用目录从原来的application更改为app,之所以做这个调整是为了让新手更容易理解应用的命名空间对应,不至于产生不必要的困惑。
- 初始目录 :
1 | www |
应用命名空间类似于
1 | namespace app\controller; |
如果你需要更改根命名空间为top
,有两种办法。
- 一种是修改
composer.json
文件的autoload
,这样可以不改变目录名。
1 | "psr-4": { |
- 第二种办法是直接修改你的
app
目录为top
。
无论使用哪一种方法,最后在入口文件中设置根命名空间名称。
1 |
|
如果你的 admin
应用不在 app
目录下面,有完全独立的命名空间例如
1 | \think\admin; |
就可以在入口文件admin.php
中进行指定
1 |
|
这个应用放在什么位置取决于你的命名空间自动加载路径,这一设计让你的应用可以通过composer
来加载。
多应用模式
多应用模式下面,除了应用目录的区别外,runtime
目录下面会自动创建各个应用的子目录(注意,这个目录同样适用于composer
加载的应用),但你只需要通过App::getRuntimePath()
方法获取当前应用的runtime
目录。
1 | runtime/home/ |
多个应用的路由定义文件都是独立的,在route
目录下面创建对应目录的子目录存放每个应用的路由定义。
1 | route/home/ |
多个应用允许加载统一的公共文件。
1 | app/common.php |
对于配置文件而言,config
目录下为应用公共配置,config
下子目录则为单个应用的独立配置。
1 | config/ |
可能有人认为现在不同的应用是独立的入口文件,每个应用之间没法互通了,其实这个理解是错误的。不同的应用仍然是可以相互调用的,毕竟类库都是基于命名空间的。
单应用模式
上面的目录结构其实是多应用设计,和之前版本一样同样支持单应用模式(之前版本其实是单一模块模式)如果你使用的是单应用的话,目录结构其实就变成了下面的结构。
1 | www |
系统的一个默认判断单应用的规则是app
目录下面如果存在controller
目录,则判断当前为单应用模式。如果你更改了默认的访问控制器层的名称(或者刚好有一个应用名称也叫controller
),那么可以在入口文件里面调用 multi(false)
来设置为单应用模式。
1 |
|
单应用模式下,如果需要更改命名空间,setNamespace
和 setRootNamespace
方法是等效的。
数据库和模型的变化
总体来说,在数据库和模型层面,5.2
的改动并不大,只是因为强类型变量的约束会导致一些用法的差异,以及一些统一和废弃的方法会导致查询代码的调整。
5.2
版本目前尚未正式发布,在正式发布之前可能仍然会存在变化。
新特性
强类型严格模式
新版核心全面启用了严格模式,避免因为方法参数类型模糊而导致的规范不一或者潜在问题。
Db
使用门面对象
新版的Db
类不再是静态类,需要使用 think\facade\Db
门面进行静态代理。
1 | \think\facade\Db::name('user')->find(); |
重构的fetchSql
方法
查询类的fetchSql
方法返回了一个新的think\db\Fetch
类,获取查询SQL的操作和查询操作完全隔离。另外一个副作用是可以使得查询方法的返回值更加规范。Fetch
类目前已经支持动态查询方法。
1 | Db::name('user')->where('id', 1); // 返回\think\db\Query对象实例 |
增加乐观锁功能
和软删除一样,增加了一个 think\model\concern\OptimLockTrait
用于方便引入扩展模型的乐观锁功能。
1 |
|
增加fetchArray
方法
模型的查询可以通过显式调用fetchArray
方法使得查询结果返回数组而不是模型对象和数据集,适用于一些图表控件的数据输出。
1 | // 返回模型对象 |
模型增加Schema
定义
模型类增加
schema
属性,用于完整定义模型对应数据表的字段信息,
可以避免查询的时候获取数据表字段信息而无需生成Schema
缓存。并且该属性中定义字段类型支持使用php
类型定义。
需要注意和field
/type
属性的区别,field
属性仅用于定义当前模型允许写入的字段,而type
属性则仅用于定义数据字段的类型强制转换。
1 |
|
模型延迟保存机制
模型增加延迟保存方法lazySave
,调用该方法后不会马上保存数据,仅仅是保存在内存中,当前模型对象销毁的时候或者下次显式调用save
方法的时候都会自动保存到数据库。
1 | $user = User::find(1); |
join
系列方法增加参数绑定支持
join
方法(包括leftJoin
/rightJoin
/fullJoin
方法)支持手动参数绑定。
增加tableRaw
方法
增加tableRaw
方法使用表达式方法定义当前查询的数据表。
查询缓存支持闭包情况
改进查询缓存方法支持使用闭包查询的情况。
增加 withAttrs
方法
由于参数强制类型的关系,withAttr
方法不支持传入数组,必须使用withAttrs
方法传入数组批量设置字段获取器。
废弃功能和方法
废弃了一些目前已经很少用到或者不建议使用的功能,以及对容易混淆的一个功能多个用法进行了统一。
取消数据分表功能
取消了数据库分表功能,建议直接使用数据库的分区功能替代,更灵活和性能更好,同时取消了Query
类的getPartitionTableName
和partition
方法。
取消了get
/all
方法
无论使用Db
类还是模型类查询,全部统一使用find
/select
方法,取消了之前模型类额外提供的get
/all
方法。
取消findOrEmpty
方法
取消了Query
类的findOrEmpty
方法,当模型使用find
方法查询的时候,数据不存在自动返回一个空模型对象,无需再使用findOrEmpty
方法了。
取消relation
方法
取消了Query
类的relation
方法,模型的关联获取直接使用关联属性方式惰性获取。
取消了readMaster
方法
取消了Query
类和模型类的readMater
方法,由于该方法使用了静态属性容易导致Swoole
等常驻内存的环境下读取错乱。需要的时候可以用master
方法手动切换主库读取。
取消fetchPdo
方法
取消了Query
类的fetchPdo
方法,需要的时候直接使用getPdo
方法替代。
取消查询方法传入Query
对象
取消Query
类的CURD
查询方法传入当前对象,如果需要请使用闭包替代。
取消全局查询范围base
方法
取消模型类的全局查询范围base
方法,改由使用globalScope
属性定义(数组)需要全局查询的查询范围方法。或者在db($scope)
方法中传入全局查询范围。如果是静态查询,可以使用useGlobalScope($scope)
。
取消 db
和 model
助手函数
这两个助手函数5.1
版本已经不再建议使用了,新版直接废弃掉这两个助手函数,请指教使用\think\facade\Db
类和实际的模型类调用。
取消 setInc
/setDec
方法
取消Query
类的setInc
/setDec
方法,统一使用inc
/dec
方法替代,同时改进了inc
/dec
方法支持延时更新。
取消setField
方法
取消Query
类的setField
方法,请直接使用data
方法或者update
方法。
取消__TABLE_NAME__
支持
table
方法取消__TABLE_NAME__
支持,必须明确调用完整表名或者使用name
方法。
取消whereOr
等方法传入Query
对象
除了where
方法本身可以传入Query
对象外,其它的所有where
查询方法(例如whereOr
/whereExp
等)都不再支持传入Query
对象。
取消resultset_type
配置参数
数据集查询结果不再受resultset_type
配置参数影响,默认情况下,Db查询统一返回数组,模型查询统一返回模型对象和模型数据集对象。如果Db查询的时候也需要返回数据集的话,可以显式调用fetchCollection
方法。
with
方法和withJoin
独立
无需在模型关联方法中定义是否使用JOIN
查询,只有在明确调用withJoin
的时候才会使用JOIN
查询。
路由的调整和改进
ThinkPHP5.2
的路由部分,也和其它组件一样,做了精简和优化,主要包括如下方面:
取消路由定义的返回数组形式
因为不利于路由缓存生成,路由定义文件取消了返回数组的方式定义路由,必须采用路由方法注册路由。
例如:
1 | return [ |
必须改成:
1 | Route::get('hello/:name', 'index/hello'); |
多应用的路由定义文件位置
单应用模式下,路由定义文件和之前一样就在route
目录下面,如果你的项目是采用了多应用的话,每个应用的路由定义和匹配都是独立的,也没有模块的概念,路由定义文件的位置应该是在route/应用子目录
下面,例如:
1 | route/index/route.php // index应用的路由定义文件 |
默认的URL规则变成了:
1 | http://域名/入口文件(或者应用名)/控制器名/操作名 |
应用的路由规则其实是定义的入口文件(或者应用名)后面的URL部分,而不包含应用。
自动多应用
最新的5.2版本可以支持在同一个入口文件中访问多个不同的应用(之前必须每个应用添加一个对应的入口文件)。
例如在index.php
入口文件中使用:
1 | (new App())->autoMulti() |
就可以不必创建入口文件自动通过URL
访问多个应用
1 | http://serverName/index.php/admin |
如果你的默认应用不是index
(默认为入口文件名),那么可以通过name
方法指定默认应用。
1 | (new App())->autoMulti() |
支持应用名的别名映射,例如:
1 | (new App())->autoMulti([ |
如果需要对某个应用进行自定义,可以使用
1 | (new App())->autoMulti([ |
取消别名路由
因为使用场景有限和性能开销问题,取消原来的别名路由功能,建议使用资源路由或者单独的路由替代。
取消快捷路由
因为使用场景有限和不太符合规范,取消了原来的控制器快捷路由功能。
取消空控制器和空操作
原来的空控制器和空操作功能已经取消,请使用MISS
路由功能替代,而且可以支持给不同的路由分组设置MISS
路由。同时废弃empty_controller
配置。
取消控制器自动搜索
由于性能原因,取消了路由的多级控制器自动搜索功能,请在路由规则定义中明确指定要路由的多级控制器。
路由功能独立设计
路由功能不再固定执行,而且设计成为AppInit
事件的响应监听,并且可以在项目的事件定义里面配置,系统默认的定义配置如下:
app\event.php
1 | return [ |
在AppInit
事件中会执行think\listener\RouteCheck
类,如果你的应用完全不需要使用任何的路由功能,可以在配置文件中取消定义即可,系统会执行默认的URL
调度(也即是控制器/操作)。
取消注册方法的 option
和 pattern
参数
取消路由注册方法(包括rule
/get
/post
/put
/delete
/patch
/miss
/group
等方法)的option
和pattern
参数,全部改成方法调用形式,例如原来的:
1 | Route::get('hello/:name', 'index/hello', [ 'ext' => 'html'], [ 'name' => '\w+']); |
需要改成
1 | Route::get('hello/:name', 'index/hello') |
路由分组定义不再支持数组
因为不利于分组的嵌套功能,路由分组定义不再支持数组,只能使用闭包方式定义,例如:
1 | Route::group('blog', [ |
必须改成
1 | Route::group('blog', function() { |
如果你需要注册一个虚拟的路由分组,可以直接在第一个参数使用闭包
1 | Route::group(function() { |
取消了url_controller_layer
配置
改为在入口文件中使用controllerLayer
方法设置。
1 | (new App())->controllerLayer('Action') |
取消class_suffix
配置
改为在入口文件中使用useClassSuffix
方法设置。
1 | (new App())->useClassSuffix(true) |
同时取消controller_suffix
和class_suffix
配置参数。
取消 mergeExtraVars
方法和对应参数
改为在路由规则中明确指定变量规则。
header
方法参数类型调整
由于强类型约束的原因,header
方法改为仅支持数组参数传入。
使用强类型参数
由于全面启用强类型参数,并且使用严格模式,所以一定要注意参数的类型。