# 值得升級到ThinkPHP`5.1`的18個理由??
ThinkPHP`5.1`從2018年初發布到現在,一路小步快跑,快速迭代的同時也更新了大量的新特性。
>[danger] 那么到底是否值得升級到新版呢?本文就和大家分享下值得升級到`5.1`的18個理由。
[TOC=2,2]
## 1、快速啟動測試服務器:直接跨過門檻學框架
新手服務器環境不會搭?`pathinfo`不支持?告別這些煩惱吧,`5.1`內置了一個快速啟動測試服務器的指令,你只需要在命令行下切換到項目根目錄下面輸入:
~~~
php think run
~~~
即可在`localhost:8000`啟動一個測試服務器,而無需任何其它的WEB服務器環境,告別新手搭建環境各種問題的困惑。
相比較而言,在`5.0`中,必須使用
~~~
php -S localhost:8000 public/router.php
~~~
當然,該指令也支持指定端口和地址(域名),下面就是指定通過`tp.com`(需要自己添加host)域名的80端口訪問。
~~~
php think run -H tp.com -p 80
~~~
## 2、對象容器引入和依賴注入改進:實用高逼格
`5.1`正式引入了對象容器,可以更方便的快速存取對象和管理依賴注入。這是`5.1`基礎架構的一大調整,5.0沒有容器的概念,所有的依賴對象都在請求對象中,依賴注入雖有支持但不夠規范也不通用化。有了容器對象,所有的依賴對象都可以在容器里面進行統一的實例化或者綁定,需要的時候可以直接拿出來,對于解耦和減少直接依賴很有幫助。
`5.1`的應用類`think\App`本身就是容器,同時還充當了容器的管理對象,你不需要直接操作容器類就能對容器中的對象實例進行存取。而App類通常是在入口文件中實例化的,也就是說在App類實例化的同時,這個容器對象就已經準備好了。
而App類本身也提供了門面方式的靜態調用,因此,你可以像下面一樣方便調用。
~~~php
use think\facade\App;
// 綁定對象實例到容器
App::bindTo('myClass',$obj);
// 為了避免容器過大 通常只是綁定一個類而不是對象
App::bindTo('myClass','namespace\ClassName');
// 快速獲取對象實例
$obj = App::make('myClass');
// 無需綁定操作即可獲取對象實例
$obj = App::make('namespace\ClassName');
~~~
容器對象中的實例默認都是單例的,如果你需要獲取新的對象實例,可以在make的時候指定總是重新實例化
~~~php
// 創建一個新的對象實例
$obj = App::make('namespace\ClassName',true);
// 如果需要實例化的時候傳入參數,則使用
$obj = App::make('namespace\ClassName', ['name' => 'think'], true);
~~~
當然,這個只是容器內部的調用機制,實際到應用層面,大多數時候容器對象實例的獲取是在依賴注入的時候自動完成的,因此你可能根本不需要用到上面的代碼或者說關心容器的存在。下面就是一個典型的依賴注入的例子:
~~~php
<?php
namespace app\index\controller
use namespace\ClassName;
class My
{
// 調用test操作方法的時候會自動從容器中獲取ClassName對象實例
public function test(ClassName $class){
// 調用對象的方法或者獲取屬性
$class->fun();
}
}
~~~
ThinkPHP`5.1`沒有服務提供者的概念,如果你需要對容器中的對象進行自定義實例化,可以在你的對象中添加`__make`靜態方法來完成。
~~~php
use think\App;
class ClassName
{
/**
* 名稱
* @var string
*/
protected $name;
/**
* 構造方法
* @access public
*/
public function __construct($name = '')
{
$this->name = $name;
}
public static function __make(App $app)
{
$name = $app['config']->get('app_name');
return new static($name);
}
}
~~~
現在當你在操作方法中依賴注入ClassName對象(或者通過容器的make方法獲取對象實例)的時候,就會自動調用`__make`方法進行自定義實例化。
> 正因為容器的引入,使得`5.1`的依賴注入得以更加完善,并且支持了更多的依賴注入的場景,包括控制器架構函數,操作方法,事件響應,路由定義,模型事件等等。
## 3、增加門面對象:類的小助理
`5.1`的核心類基本上都改造成了動態類,對需要提供靜態調用的類則改為提供門面對象支持,好處是可以更好的支持單元測試,由于容器的支持而使得門面對象天生具有單例的特性。
> 但因為用法的改變同時也讓門面變成了`5.0`升級到`5.1`最大的障礙,因為你不得不調整類庫的引入。
很典型的`5.0`中經常使用的`Route`類、`Session`類在`5.1`中類的方法本身沒有變化,只是不再是原來的`think\Route`和`think\Session`靜態類,必須改成門面靜態代理類:
~~~php
use think\facade\Route;
use think\facade\Session;
Route::rule('hello/:name','index/hello');
Session::get('user_name');
~~~
和依賴注入一樣,通過門面對象操作的時候會自動獲取容器中的對象實例(如果不存在的話則會自動實例化),因此你不用關心對象是如何實例化的。你操作`think\facade\Route`就和操作`think\Route`類是一個效果(除了使用的是靜態方法之外)。門面對象唯一的不足是對IDE的自動提示不夠,但可以通過給門面類添加注釋解決,系統內置的門面類均有自動提示。
## 4、路由更對象化:又雙叒叕提速??
`5.1`的路由基本上完全重構了,但最大程度的保留(或者說兼容)了`5.0`的用法,把原本的一個`Route`類拆分成獨立的多個職責明確的類庫,并且優化了路由匹配的算法,而且支持路由解析的緩存,極大提升了路由的性能。
### 路由規則的變量用法改進
路由定義方面主要對域名路由和路由分組的功能進行了強化,以及路由規則的更靈活定義。
之前的路由規則中變量分兩種,普通變量和組合變量定義,新版把這兩種合二為一了(也就是說兩種變量沒有任何區別,僅僅是表現方式不同,而且是出于兼容考慮)。你現在完全可以在路由規則中以任何方式定義路由變量。
例如你可以使用下面的路由規則而不用管目前的URL分隔符是什么:
~~~php
Route::rule('item/:name_:id', 'order/index');
Route::rule('product-<category>:name', 'product/item');
~~~
另外,新版路由定義兩種變量方式`:name`和`<name> `可以混合使用,但建議統一使用`<name>`,在性能上略有優勢(實際上,最終解析的時候系統會統一解析成后者)。
### 路由匹配算法改進
路由檢測其實是最耗性能的,尤其是路由匹配這塊,因為基本上都是采用的正則匹配。在`5.0`版本之前,如果定義了100個路由,那么最后的那個路由規則可能需要遍歷100次才能正確匹配到路由,而且每個路由規則中的路由變量都是單獨匹配的,所以這個路由匹配的性能開銷是隨著路由定義的數量指數上升的。
`5.1`版本系統對路由的匹配這塊進行了算法優化,靈感來自于`fastRoute`。基本思想是分兩個步驟優化(思想其實很容易懂,但技術層面比較復雜,所以想了解怎么實現的話還是仔細看代碼吧~本文只闡述思想)。
第一個步驟是對單個路由規則的匹配算法進行調整,不按照變量進行多次匹配,而是把路由變量的正則合并到一起,然后整個路由規則只匹配一次(如果這個路由規則都是靜態的,那么基本上不需要正則匹配,采用的是更快的非正則檢測方式)。這個是新版默認就開啟的,相比較之前的版本,性能已經提升明顯。
但路由的性能提速遠非如此簡單,第二個步驟的優化策略是如果當前匹配的路由分組下面有多個路由規則(確切的說是滿足當前請求類型的),則把這些滿足條件的路由規則合并成一個正則表達式進行路由匹配。如果你的路由分組下面有100個滿足條件的路由規則,如果要訪問最后的路由規則,之前的方式可能需要遍歷100次,而新版只需要進行一次匹配。就算加上路由規則的合并開銷,仍然是值得的。
而且新版路由支持開啟路由緩存(僅在部署模式下有效),在定義了大量的路由規則之后,開啟該緩存可以明顯提升路由解析性能,而且路由規則越多越明顯。
由于更加對象化,新版的路由更建議采用方法定義,`5.0`的路由參數在`5.1`中都可以用鏈式方法設置,還可以享受IDE的自動提示功能。
~~~php
// 給路由規則添加參數
Route::get('hello/:name','index/hello')
->ext('html')
->ajax()
->https()
->domain('thinkphp.cn');
~~~
新版一個很有用的參數是可以用`filter`方法檢測當前請求的參數是否匹配
~~~php
// 給路由規則添加參數
Route::get('hello/:name','index/hello')
// 只有當前請求的type參數為vip的時候才匹配路由
->filter('type', 'vip');
~~~
## 5、注解路由:定義路由新姿勢
> 5.1支持注解路由,可以在你的控制器文件中通過注解的方式快速定義路由,在調試模式下實時生效,在部署模式下則需要運行一下指令生成注解路由。注解路由可以和路由定義文件同時定義,并且注解路由優先。
開啟注解路由后,你只需要直接在控制器類的方法注釋中定義(通常稱之為**注解路由**),例如:
~~~php
<?php
namespace app\index\controller;
class Index
{
/**
* @param string $name 數據名稱
* @return mixed
* @route('hello/:name')
*/
public function hello($name)
{
return 'hello,'.$name;
}
}
~~~
就相當于注冊了一條下面的路由規則
~~~
Route::rule('hello/:name','index/hello');
~~~
默認注冊的路由規則是支持所有的請求,如果需要指定請求類型,可以在第二個參數中指定請求類型:
~~~php
<?php
namespace app\index\controller;
class Index
{
/**
* @param string $name 數據名稱
* @return mixed
* @route('hello/:name','get')
*/
public function hello($name)
{
return 'hello,'.$name;
}
}
~~~
相當于注冊了一條下面的路由規則
~~~
Route::get('hello/:name','index/hello');
~~~
如果有路由參數和變量規則需要定義,可以直接在后面添加方法,例如:
~~~php
<?php
namespace app\index\controller;
class Index
{
/**
* @param string $name 數據名稱
* @route('hello/:name','get')
* ->https()
* ->pattern(['name' => '\w+'])
*
* @return mixed
*/
public function hello($name)
{
return 'hello,'.$name;
}
}
~~~
就相當于注冊了一條下面的路由規則
~~~php
Route::get('hello/:name','index/hello')
->https()
->pattern(['name' => '\w+']);
~~~
如果是資源路由則更為簡單,在類的開頭注釋中添加注解就行了,例如:
~~~php
<?php
namespace app\index\controller;
/**
* @route('blog')
*/
class Blog
{
public function index()
{
}
public function read($id)
{
}
public function edit($id)
{
}
}
~~~
就相當于注冊了一條下面的路由規則
~~~
Route::resource('blog','blog');
~~~
## 6、跨域請求更簡單:漂洋過域來看你
如果某個路由或者分組需要支持跨域請求,可以使用
~~~php
Route::get('new/:id', 'News/read')
->ext('html')
->allowCrossDomain();
~~~
>[danger] 跨域請求一般會發送一條`OPTIONS`的請求,一旦設置了跨域請求的話,不需要自己定義`OPTIONS`請求的路由,系統會自動加上。
>
跨域請求系統會默認帶上一些Header,包括:
~~~
Access-Control-Allow-Origin:*
Access-Control-Allow-Methods:GET, POST, PATCH, PUT, DELETE
Access-Control-Allow-Headers:Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-Requested-With
~~~
你可以添加或者更改Header信息,使用
~~~
Route::get('new/:id', 'News/read')
->ext('html')
->header('Access-Control-Allow-Origin','thinkphp.cn')
->header('Access-Control-Allow-Credentials', 'true')
->allowCrossDomain();
~~~
## 7、引入中間件支持:分工更明確
`5.1`正式引入中間件,包括路由中間件和控制器中間件。例如通過對路由分組或者路由單獨設置中間件,可以靈活的控制訪問權限,并且把中間件的邏輯和你的控制器邏輯可以分離設計,最大程度的復用中間件。
> 中間件的執行是在控制器的操作方法執行前后(所以能替代之前的路由后置行為,控制器的初始化操作和前置操作行為,但不能替代所有的行為,這點一點要區分清楚),所以包含前置中間件和后置中間件兩種類型,你可以根據需求定義不同的中間件。路由中間件其實就是在路由中定義好要執行哪個中間件,而控制器中間件是當你沒有使用路由的情況下,在控制器里面直接定義要執行的中間件。
可以通過命令行快速生成一個中間件類,然后加上你的業務邏輯。
~~~
php think make:middleware CheckAuth
~~~
會自動生成一個 `app\http\middleware\CheckAuth`的中間件類,然后修改`handle`方法代碼如下:
~~~php
<?php
namespace app\http\middleware;
class CheckAuth
{
public function handle($request, \Closure $next)
{
echo 'before check<br/>';
$result = $next($request);
echo 'after check<br/>';
}
}
~~~
你可以在你的路由定義中指定中間件
~~~php
Route::group('hello', function(){
// 定義分組路由
// 。。。
Route::get(':name', 'index/hello');
})->middleware('CheckAuth');
~~~
如果要指定多個中間件,可以使用數組的方式
~~~
Route::group('hello', function(){
// 定義分組路由
// 。。。
})->middleware(['CheckAuth', 'CheckName']);
~~~
當你沒有使用路由的情況下,可以在控制器里面直接定義中間件,如下:
~~~
<?php
namespace app\index\controller;
use think\Controller;
class Index extends Controller
{
protected $middleware = ['CheckAuth'];
public function index()
{
return 'index';
}
public function hello()
{
return 'hello';
}
}
~~~
如果你需要在中間件和控制器之間傳遞參數,可以通過給`Request`對象賦值
~~~
<?php
namespace app\http\middleware;
class CheckAuth
{
public function handle($request, \Closure $next)
{
$request->auth = 'admin';
return $next($request);
}
}
~~~
> 注意,傳遞的變量名稱不要和`param`變量有沖突。
然后在控制器的方法里面可以直接使用
~~~
public function index(Request $request)
{
return $request->auth; // admin
}
~~~
## 8、搜索器:查詢利器化繁為簡
> 搜索器功能對于規范和簡化數據的表單搜索非常有效,甚至還能支持排序和多表查詢,讓你的控制器代碼減少到最低。
你不需要在控制器中或者模型的方法中使用大量繁瑣而且重復的查詢代碼,只需要在模型類中添加類似下面的搜索器方法,化繁為簡。
~~~
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
public function searchNameAttr($query, $value, $data)
{
$query->where('name','like', $value . '%');
}
public function searchCreateTimeAttr($query, $value, $data)
{
$query->whereBetweenTime('create_time', $value[0], $value[1]);
}
}
~~~
然后,我們可以使用下面的查詢
~~~
User::withSearch(['name','create_time'], [
'name' => 'think',
'create_time' => ['2018-8-1','2018-8-5'],
'status' => 1
])
->select();
~~~
自動會調用`name`和`create_time`字段對應的搜索器方法完成查詢條件。
> 事實上,除了在搜索器中使用查詢表達式外,還可以使用其它的任何查詢構造器以及鏈式操作。
例如,你需要通過表單定義的排序字段進行搜索結果的排序,可以使用
~~~
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
public function searchNameAttr($query, $value, $data)
{
$query->where('name','like', $value . '%');
if (isset($data['sort'])) {
$query->order($data['sort']);
}
}
public function searchCreateTimeAttr($query, $value, $data)
{
$query->whereBetweenTime('create_time', $value[0], $value[1]);
}
}
~~~
然后,我們可以使用下面的查詢
~~~
User::withSearch(['name','create_time', 'status'], [
'name' => 'think',
'create_time' => ['2018-8-1','2018-8-5'],
'status' => 1,
'sort' => ['status'=>'desc'],
])
->select();
~~~
## 9、生成器:緩解大數據查詢的內存開銷
你可以在查詢的時候使用PHP的生成器特性,使用`cursor`查詢可以讓你在不耗費內存的情況下處理大量數據集結果。
~~~
$users = User::where('status', 1)->limit(10000)->curosr();
// users 是一個Generator對象
foreach($users as $user) {
// 對數據進行處理
// 。。。
}
~~~
如果不使用生成器對象,從數據庫里面獲取1萬條數據就有可能讓內存暴增。
## 10、數據集增強:用過都說好
> `5.1`的模型查詢統一返回模型對象或者包含模型的數據集對象,你可以和模型一樣操作數據集對象。并且改進了數據集對象對數據的處理能力。
其實數據集的用法和數組基本一樣,例如可以遍歷和直接獲取某個元素。
~~~
// 模型查詢返回數據集對象
$list = User::where('id', '>', 0)->select();
// 獲取數據集的數量
echo count($list);
// 直接獲取其中的某個元素
dump($list[0]);
// 遍歷數據集對象
foreach ($list as $user) {
dump($user);
}
// 刪除某個元素
unset($list[0]);
~~~
唯一的不同恐怕就是判斷數據集是否為空,不能直接使用`empty`判斷,而必須使用數據集對象的`isEmpty`方法判斷,例如:
~~~
$users = User::select();
if ($users->isEmpty()) {
echo '數據集為空';
}
~~~
不過通用的辦法是判斷下數據集的元素
~~~
$users = User::select();
if (count($users)==0) {
echo '數據集為空';
}
~~~
你可以使用模型的`hidden`/`visible`/`append`/`withAttr`方法進行數據集的輸出處理,例如:
~~~
// 模型查詢返回數據集對象
$list = User::where('id', '>', 0)->select();
// 對輸出字段進行處理
$list->hidden(['password'])
->append(['status_text'])
->withAttr('name', function($value, $data) {
return strtolower($value);
});
dump($list);
~~~
如果需要對數據集的結果進行篩選和排序,可以使用
~~~
// 模型查詢返回數據集對象
$list = User::where('status', 1)->select()
// 對數據集進行數據過濾以及排序
->where('name', 'think')
->where('score', '>', 80)
->order('create_time', 'desc');
dump($list);
~~~
還有大量的實用方法等你去挖掘~
## 11、JSON字段查詢:就是如此簡單
你可以像使用對象一樣來操作JSON字段,并且字段不必是JSON類型,支持varchar類型,只要你存入的數據格式是JSON類型。
定義User模型類
~~~
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
// 設置json類型字段
protected $json = ['info'];
}
~~~
定義后,寫入JSON數據。
~~~
$user = new User;
$user->name = 'thinkphp';
// 寫入JSON類型字段數據
$user->info = [
'email' => 'thinkphp@qq.com',
'nickname '=> '流年',
];
// 或者用對象方式
$info = new StdClass();
$info->email = 'thinkphp@qq.com';
$info->nickname = '流年';
$user->info = $info;
$user->save();
~~~
查詢JSON數據
~~~
$user = User::get(1);
echo $user->name; // thinkphp
echo $user->info->email; // thinkphp@qq.com
echo $user->info->nickname; // 流年
~~~
查詢條件為JSON數據
~~~
$user = User::where('info->nickname','流年')->find();
echo $user->name; // thinkphp
echo $user->info->email; // thinkphp@qq.com
echo $user->info->nickname; // 流年
~~~
支持設置模型的`JSON`數據返回數組。
~~~
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
// 設置json類型字段
protected $json = ['info'];
// 設置JSON數據返回數組
protected $jsonAssoc = true;
}
~~~
設置后,查詢代碼調整為:
~~~php
$user = User::get(1);
echo $user->name; // thinkphp
echo $user->info['email']; // thinkphp@qq.com
echo $user->info['nickname']; // 流年
~~~
可以單獨設置JSON字段屬性的類型
~~~
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
// 設置json類型字段
protected $json = ['info'];
// 設置JSON字段的類型
protected $jsonType = [
'user_id' => 'int'
];
}
~~~
沒有定義類型的屬性默認為字符串類型,因此字符串類型的屬性可以無需定義。
更新JSON數據也是類似
~~~php
$user = User::get(1);
$user->name = 'kancloud';
$user->info->email = 'kancloud@qq.com';
$user->info->nickname = 'kancloud';
$user->save();
~~~
## 12、動態定義獲取器:Db類也可以用獲取器
你可以不用在模型里面定義獲取器方法,而是可以使用`withAttr`方法動態定義獲取器(而且適用于Db類的查詢結果)。
~~~
User::withAttr('name', function($value, $data) {
return strtolower($value);
})->select();
~~~
>[danger] 如果同時還在模型里面定義了相同字段的獲取器,則動態獲取器優先,也就是可以臨時覆蓋定義某個字段的獲取器。
支持對關聯模型的字段使用動態獲取器,例如:
~~~
User::with('profile')->withAttr('profile.name', function($value, $data) {
return strtolower($name);
})->select();
~~~
并且支持對`JSON`字段使用獲取器,例如在模型中定義了`JSON`字段的話:
~~~
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
// 設置json類型字段
protected $json = ['info'];
}
~~~
可以使用下面的代碼定義JSON字段的獲取器。
~~~
User::withAttr('info.name', function($value, $data) {
return strtolower($name);
})->select();
~~~
可以在查詢之后使用`withAttr`方法。
~~~
User::select()->withAttr('name', function($value, $data) {
return strtolower($value);
});
~~~
Db類也可以支持獲取器定義。
~~~
Db::name('user')->withAttr('name', function($value, $data) {
return strtolower($value);
})->select();
~~~
上面的代碼,查詢的數據集數據中的`name`字段的值會統一進行小寫轉換。
支持對JSON字段定義獲取器。
~~~
$user = Db::name('user')
->json(['info'])
->withAttr('info.name', function($value, $data) {
return strtolower($value);
})->find(1);
dump($user);
~~~
查詢結果返回的時候,會自動對`info`字段(`JSON`字段)的`name`屬性使用獲取器操作。
## 13、數組對象查詢:既有情懷又夠貼心
由于5.1的數組查詢方式改變導致很多人不敢升級,對于習慣或者重度依賴5.0數組查詢條件的用戶來說,可以選擇數組對象查詢,該對象完成了普通數組方式查詢和系統的查詢表達式之間的橋接。
使用方法如下:
~~~
use think\db\Where;
// 這個數組條件用法完全和5.0一樣
// 區別只是在傳入where方法的時候使用 new Where($map) 代替 $map
$map = [
'name' => ['like', 'thinkphp%'],
'title' => ['like', '%think%'],
'id' => ['>', 10],
'status' => 1,
];
// 或者先創建Where對象(數組查詢對象)
$where = new Where;
$where['id'] = ['in', [1, 2, 3]];
$where['title'] = ['like', '%php%'];
Db::table('think_user')
->where(new Where($map))
->whereOr($where->enclose())
->select();
~~~
`enclose`方法表示該查詢條件兩邊會加上括號包起來。現在你可以毫不猶豫的升級到`5.1`版本而不用擔心花費大量時間重構你的查詢代碼了。
## 14、查詢為空的改進:懶人真多
很多新手都有一個困惑,使用find或者模型的get方法查詢的時候,都忽略要先判斷下數據是否存在,才能進行后續操作,現在方便了,你只需要在查詢之前調用`allowEmpty`方法,或者直接使用`findOrEmpty`方法進行查詢,當查詢數據不存在的時候返回空數組或者空的模型對象。
~~~
// 始終返回一個User模型對象
$user = User::findOrEmpty(1024);
// 始終返回數組,而不是null
$user = Db::name('user')->findOrEmpty(1024);
~~~
## 15、Swoole/Workerman支持:如虎添翼
`5.1`核心調整后可以更簡單的支持`Swoole`,使用官方的擴展(`topthink/think-swoole`)的話,還可以直接通過命令行指令啟動`Swoole`服務,讓你的應用可以直接部署在`Swoole`上,從而帶來性能的再次提升。如果要在`5.0`上面支持這些,幾乎不可能或者會非常困難。
直接在命令行下啟動Swoole HTTP Server服務端。
~~~
php think swoole
~~~
啟動完成后,會在`0.0.0.0:9501`啟動一個HTTP Server,可以直接訪問當前的應用。
`swoole`的參數可以在應用配置目錄下的`swoole.php`里面配置(具體參考配置文件內容)。
如果需要使用守護進程方式運行,可以使用
~~~
php think swoole -d
~~~
支持`reload`/`stop`/`restart`等操作
~~~
php think swoole reload
~~~
并且可以支持文件監控,項目代碼修改會自動`reload`服務,而無需手動重啟,方便代碼調試。
如果你要啟動其它的服務(例如websocket服務),可以使用
~~~
php think swoole:server
~~~
會在`0.0.0.0:9508`啟動一個Websocket服務。
同樣通過`topthink/think-worker`擴展提供了對`workerman`和`GatewayWorker`的支持。
## 16、驗證類改進:對象化定義驗證規則
驗證規則的定義也可以告別數組方式,而改用對象化的方式,而且也新增了一些內置驗證規則。
~~~
$validate = new \think\Validate;
$validate->rule('age', 'number|between:1,120')
->rule([
'name' => 'require|max:25',
'email' => 'email'
]);
$data = [
'name' => 'thinkphp',
'email' => 'thinkphp@qq.com'
];
if (!$validate->check($data)) {
dump($validate->getError());
}
~~~
上面的寫法在5.1中可以改為對象化的方式
~~~
use think\validate\ValidateRule as Rule;
$validate = new \think\Validate;
$validate->rule('age', Rule::isNumber()->between([1,120]))
->rule([
'name' => Rule::isRequire()->max(25),
'email' => Rule::isEmail(),
]);
$data = [
'name' => 'thinkphp',
'email' => 'thinkphp@qq.com'
];
if (!$validate->check($data)) {
dump($validate->getError());
}
~~~
原來`5.0`的模型自動驗證已經取消了,必須改為控制器自動驗證或者使用路由驗證。總結一句話,驗證操作應該盡可能的提前。
## 17、配置和路由定義獨立目錄:地位提升
`5.1`配置文件和路由定義的目錄層級提升(在應用同級目錄),配置文件支持統一管理,不用在各個模塊目錄下面尋找,但仍然支持在模塊的`config`目錄下面單獨定義,便于模塊化開發。
配置全部使用二級方式,每個配置文件的文件名就是一級配置名,清晰直觀,需要增加新的配置文件直接放到配置目錄下即可,無需任何的擴展配置。如果你安裝了`Yaconf`擴展,那么還支持使用`Yaconf`定義配置。
路由定義文件則統一放到`route`目錄,支持分開多個文件進行路由管理。
## 18、改進的日志支持:更好用了唄
`5.1`的日志遵循`PSR-3`日志規范,相比較`5.0`版本,增加如下支持:
* 支持最大日志文件數和自動清理;
* 支持單一日志文件;
* 支持關閉當前日志寫入;
* 對命令行日志的更好支持;
* 日志可以支持JSON格式,便于各種日志分析工具,包括阿里云的日志管理工具。
## 總結:升級無悔,再戰五百年
其實上面提到的特性沒法完全涵蓋5.1的特性,尤其是路由、查詢以及模型這塊做了大量的細節改進,更多的`5.1`改進,我建議你參考下詳細的[更新日志](http://www.hmoore.net/manual/thinkphp5_1/354156)。
>[danger] 總結來說,`5.1`版本比`5.0`版本更加規范和更接近現代化開發,所以如果你還在`5.0`和`5.1`之間猶豫不決的話,還是推薦更優秀的`5.1`版本。雖然`5.1`本身性能提升可能不至于很高,如果你大量使用路由的話,性能提升還是相當顯著的。而且益于對`Swoole`和`Workerman`的支持,性能還可以提升一個層次,不過`5.0`升級到`5.1`并不是無縫升級的,有一定工作量(官方提供了詳細的升級指導),但長期來說,這點成本仍然是值得的。最后,祝大家早日掌握5.1開發~
- 值得升級到5.1的18個理由
- 5.1.7版本新特性
- JSON字段類型在ORM中的使用
- 文件下載響應對象
- 教你使用5.1的數組對象查詢
- 模型三大利器之一:搜索器
- 在ThinkPHP中使用Yaconf
- 掌握命令行的表格輸出
- 5.1.25查詢參數綁定的改進
- ThinkPHP安全規范指引
- 巧用數據集的排序功能實現統計排序
- think-orm ——基于5.1的獨立ORM庫
- think-template——基于ThinkPHP的獨立模板引擎
- ThinkPHP5.1.26版本發布——修正版本,包含安全更新
- ThinkPHP5.0和3.2再發安全更新
- 官宣:ThinkPHP發布首個LTS版本
- 你真的了解Db類和模型的正確使用姿勢么?
- 如何更有效的記錄和管理日志
- 模型三大利器之二:修改器
- ThinkPHP5.1.28版本發布——修正上一版本問題,改進關聯查詢
- 模型三大利器之三:獲取器
- API版本控制的幾種思路
- ThinkPHP5.2第一個Beta版本發布測試
- 讓你少犯錯的數據查詢基本原則
- ThinkPHP發布5.1.29版本——常規更新
- 這15個好習慣讓你更容易升級到5.2
- 如何有效提高ThinkPHP的應用性能
- 讓你提高開發效率的查詢技巧
- 模型關聯查詢不完全指南
- 5.2發布Beta2版本——統一和精簡大量用法
- ThinkPHP發布5.1.30版本——支持微秒時間字段寫入
- ThinkPHP的數據緩存使用
- ThinkPHP5.2安裝及入口文件
- ThinkPHP榮獲2018 年度最受歡迎中國開源開發框架第1名
- 5.1路由使用心得技巧
- ThinkPHP5.*版本發布安全更新
- ThinkPHP項目及代碼規范指北
- 5.2版本的設計規范指導
- ThinkPHP5.1.32版本發布——圣誕快樂
- 利用Trait特性給模型增加樂觀鎖功能
- 5.2數據庫和模型的變化(摘要)
- ThinkPHP模板引擎實現和常見問題
- ThinkPHP5.0.24版本發布——安全更新
- 不忘初心,方得始終——ThinkPHP十三周年報告
- ThinkPHP5+相關資源匯總
- 異步社區ThinkPHP周年慶專享優惠活動
- 5.2路由的調整和改進
- ThinkPHP發布5.1.33版本——包含安全更新
- ThinkPHP擴展開發指南
- ThinkPHP發布5.2Beta3版本
- ThinkPHP發布5.1.34版本——喜迎新年
- ThinkPHP發布5.2RC1版本
- ThinkPHP發布5.1.35版本——常規更新
- 5.2配置類的調整
- 5.2時間查詢的改進和優化
- 5.2RC版本升級不完全指導(僅供學習參考)
- ThinkPHP5.2版本正式變更為6.0版本
- ThinkPHP百度云云虛擬主機專享免費活動
- 事件系統以及查詢事件、模型事件的使用
- ThinkPHP6.0RC2版本發布——架構升級、精簡核心
- ThinkPHP5.1.36LTS版本發布——常規更新
- 新版Session和Cookie設計變化
- ThinkPHP5.1.37版本發布——常規更新
- ThinkPHP6.0RC3版本發布——細節完善,體驗優化
- 6.0中間件使用詳解
- Composer各大廠商鏡像地址
- ThinkPHP6.0發布計劃公告
- 「ThinkPHP開發者周刊」招募志愿者
- ThinkPHP6.0日志變化
- ThinkPHP5.1.38版本發布——常規更新
- ThinkPHP6.0RC4版本發布——ORM獨立,日志多通道支持
- ThinkORM2.0開發指南上線
- ThinkPHP6.0RC5版本發布——多應用模式獨立,中間件機制調整
- ThinkPHP6.0版本發布——程序員節福利
- ThinkPHP5.1.39LTS版本發布——常規更新
- ThinkPHP6.0.1版本發布——圣誕快樂!
- 回顧2019,展望2020!
- ThinkPHPV6.0.2版本發布——2020新春快樂!
- 周年福利系列:Swoole合作優惠
- 億速云成為ThinkPHPV6.0獨家贊助發布商??
- 新冠疫情工具和限免資源專題(保持更新中)
- 周年福利系列:創宇信用認證合作優惠
- 周年福利系列:碼云企業版限時10%優惠
- 周年福利系列:想天短說抵現優惠
- think-swoole直播:從零開始掌握swoole開發
- 周年福利系列:B2C開源電商ShopXO授權8折優惠
- 周年福利系列:LayuiAdmin 永久授權限時優惠
- ThinkPHP資源導航站上線——構建生態 服務未來
- ThinkPHP官方技術支持服務和應用服務市場上線公測
- ThinkPHP市場精選——推廣基本要素
- ThinkPHP市場精選——客服聊天專題
- ThinkPHPV6.0.3版本發布——端午安康
- ThinkPHP開發者扶持計劃
- 6.0.3版本關鍵更新及升級事項
- 「ThinkPHP開發者周刊」改版重啟
- ThinkPHP市場精選——企業建站專題
- ThinkPHP 提供統一API接口服務
- ThinkPHP市場精選——直播電商專題
- ThinkAPI服務SDK發布
- 官方服務市場啟用獨立子域名
- ThinkPHP市場精選——刷臉支付專題
- ThinkAPI推出會員服務計劃
- ThinkPHPV6.0.4版本發布——中秋國慶雙節快樂
- ThinkPHPV5.1.40版本發布——常規更新
- 1024程序員節福利走一波
- ThinkPHP V6.0.5版本發布——兼容Composer2.0
- 知識圖譜應用場景——源論技術沙龍
- ThinkPHP5.*版本改進Composer2.0的兼容
- 官方市場雙十一精選推薦
- 技術人做產品有機會么(文末送課程)
- 本周秒殺——古德云售后獲客營銷系統
- ThinkAPI服務更新——支持接口分組和PHP版本依賴調整
- PHP8新特性盤點
- PHP8新特性系列:構造器屬性提升使用及注意事項
- ThinkPHP2021新年寄語
- ThinkPHP V6.0.6&V5.1.41版本發布——兼容PHP8.0
- PHP如何更優雅地調用API接口
- ThinkPHP V6.0.7發布——修正版本
- ThinkAPI服務更新——IP白名單
- 最新版ThinkORM對于時間字段的調整
- ThinkAPI短信接口正式上線
- ThinkPHP V6.0.8版本發布——多環境變量配置支持
- 頂想云寫作服務開啟第一次公測
- ThinkSSL上線——官方SSL/TLS證書服務
- MDBootstrap國內用戶福利——ThinkPHP官方市場首發
- ThinkPHP V6.0.9版本發布——常規更新
- ThinkORM功能盤點——虛擬模型
- 全面支持主流GIT版本庫——云寫作服務第二次公測
- 云寫作服務私有化部署方案之:版本庫私有化
- 看云雙十一活動
- ThinkPHP V6.0.10LTS發布——兼容PHP8.1
- ThinkPHP V6.0.12發布——命令行兼容8.1
- 頂想云知識管理上線公測——構建企業文檔中心和知識庫
- 頂想云上線——助力生態數字化建設
- 618活動進行中——官方市場迎來一波更新
- 頂想云知識管理正式上線——看云文檔啟動遷移服務
- ThinkPHP V6.0.13發布——常規更新
- 頂想云網站助理服務上線——構建產品支持服務
- ThinkPHP發布6.1.0&6.0.14版本——安全更新
- ThinkPHP新版社區上線試運營
- ThinkAPI上架人臉核身接口——助力網站實名認證
- 辭舊迎新——舊版社區停止注冊及發帖
- ThinkPHP6.1.2版本發布——兼容PHP8.2