我們接著重構(gòu) tp5 參數(shù)校驗層的項目進行下面的代碼:
在全局異常處理之前,我們先來實現(xiàn)一下 Banner 控制器的功能:
我們在 controller 的同級目錄下新建一個 model 文件夾。在其下面新建一個 Banner 類。
(這里為了簡潔,我們的控制器類和業(yè)務類都叫做 Banner,我們通過所屬在不同的文件夾下進行區(qū)分即可)
<?php
namespace app\api\model;
class Banner{
public static function getBannerById($id){
//TODO: 根據(jù) Banner ID 號,獲取 Banner 信息
return 'banner info';
}
}
接著我們進行編輯控制器的類。由于控制器和業(yè)務類重名,所以需要在引入的時候注意:
<?php
namespace app\api\controller\v1;
use app\api\validate\IDMustBePositiveInt;
use app\api\model\Banner as BannerModel;
class Banner{
public function getBanner($id){
(new IDMustBePositiveInt())->goCheck();
$banner = BannerModel::getBannerByID($id);
return $banner;
}
}
現(xiàn)在我們來假設這一種情況,客戶端傳來了 id 為 50,由于 50 是正整數(shù),所以通過了參數(shù)校驗,但我們的數(shù)據(jù)庫中沒有 id 號為 50 的 banner,這時候我們就需要進行相應的異常處理。
為了進行演示我們在 model\Banner 中加入以下錯誤的代碼:
try{
1/0;
}
catch(Exception $e){
throw $e;
}
現(xiàn)在我們在業(yè)務類中拋出了異常,假如我們控制器中不做處理,那么就會拋給全局異常處理器處理,并返回以下 html 頁面:

這個頁面適合后端調(diào)試,但是不適合給客戶端來看,尤其是作為接口的返回來說。
有的人可能會說,返回 html 是因為開啟了 tp5 調(diào)試模式,那么我們將
config.php 中的 'app_debug' 的值改為 false,又會返回一個這樣的頁面:
那么我們在設計接口的時候該如何向客戶端返回錯誤信息呢?
基于 RESTFul 規(guī)范,我們需要定義一個統(tǒng)一的錯誤返回消息。
我們改寫一下控制器中的代碼:
class Banner{
public function getBanner($id){
(new IDMustBePositiveInt())->goCheck();
try{
$banner = BannerModel::getBannerByID($id);
}
catch(Exception $e)
{
$err = [
'error_code' => 10001,
'msg' => $e->getMessage()
];
return json($err,400); // 注意不能直接返回數(shù)組,而應該用json包一下
}
return $banner;
}
}
我們再在 Postman 里看一下返回結(jié)果:


這樣我們這種直白的方法就寫出來了,但我們反思一下,如果每一個控制器我們都要這樣繁瑣地處理異常,那么我們今后編寫代碼的思路一定難以保證十分流暢,而是會在這些異常的處理上耗費大量精力。而且這個僅僅是一個示例,實際上我們很多情況下是不可預知是否會有異常的,可能還會返回 tp5 自己的錯誤的網(wǎng)頁,對于我們 API 來說是不合適的。
現(xiàn)在我們花了大量的篇幅展示了一種錯誤的、復用性差的直白寫法,比起直接展示最終的結(jié)果,演示這些錯誤的寫法我認為也是很有必要的,因為這是我們一步一步思路的體現(xiàn)。重構(gòu)代碼不是一蹴而就的,期間代碼的寫法也會越來越抽象,所以我們需要靜下心來,不斷地完善。