tp5.1可以自定義異常接管,具體參見文檔[異常處理接管](http://www.hmoore.net/manual/thinkphp5_1/354092#_42)
但是在實際的項目開發過程中,我們可能會面對這樣的需求:
1、后端需要記錄各類異常信息
2、前端只拋出固定的錯誤信息
3、不同的異常級別對應處理方案不同
本文就簡單介紹異常處理接管的各種騷操作:
## 1、自定義異常接管類
我們首先新建一個`app\common\exception\CommonHandler`類,并在項目配置文件中,修改`exception_handle`配置。
```
use think\exception\Handle;
use think\exception\ValidateException;
class CommonHandler extends Handle
{
public function render(\Exception $e)
{
// 參數驗證錯誤
if ($e instanceof ValidateException) {
return json($e->getMessage());
}
// 其他錯誤交給系統處理
return parent::render($e);
}
}
```
這段代碼表示,當`think\exception\ValidateException`拋出異常時,返回json格式的錯誤信息。但是在實際開發過程中,我們光有異常信息拋出可能遠遠不夠,那我們來擴展一下這個功能。
## 2、自定義一個異常類
我們再建一個`app\common\exception\AppValidateException`類,用于項目內驗證類的手動拋出。
```
use think\Exception;
class AppValidateException extends Exception
{
public $msg;
public $status;
public $data;
public $url;
public function __construct($msg,$status=1,$data=[],$url='')
{
$this->msg = $msg;
$this->status = $status;
$this->data = $data;
$this->url = $url;
}
}
```
再將`app\common\exception\CommonHandler`修改一下:
```
use think\exception\Handle;
use think\exception\ValidateException;
class CommonHandler extends Handle
{
public function render(\Exception $e)
{
//自定義的異常類,注意先后順序
if($e instanceof AppValidateException){
$data['status'] = $e->status;
$data['msg'] = $e->msg;
$data['data'] = $e->data;
$data['url'] = $e->url;
return json($data);
}
// 參數驗證錯誤
if ($e instanceof ValidateException) {
return json($e->getMessage());
}
// 其他錯誤交給系統處理
return parent::render($e);
}
}
```
這樣,我們在后端使用`throw new AppValidateException('手機號碼格式錯誤');`即可直接返回json格式的數據。
## 3、日志記錄與服務監控
這個時候,老板/產品經理/其他雜七雜八人員又說,光有報錯不行,我們要記錄程序錯誤和必要的客戶信息。好的,那就給你實現。
`app\common\exception\AppValidateException`自定義異常類:
```
namespace app\common\exception;
use think\Exception;
class AppValidateException extends Exception
{
public $msg;
public $status;
public $data;
public $url;
public $level;
public function __construct($msg,$level=1,$status=1,$data=[],$url='')
{
$this->msg = $msg; //語義提示內容
$this->status = $status; //狀態碼
$this->data = $data; //返回的數組
$this->url = $url; //url,可提供給前端跳轉
$this->level = $level; //異常級別,用于日志記錄和判斷錯誤記錄等
}
}
```
`app\common\exception\CommonHandler`自定義異常接管類:
```
namespace app\common\exception;
use think\exception\Handle;
use think\exception\ValidateException;
use think\facade\Log;
class CommonHandler extends Handle
{
protected $error;
public function render(\Exception $e)
{
//自定義的異常類,注意先后順序
if($e instanceof AppValidateException){
$this->getException($e);
$this->analyze($e->level,$e->status,$e->data,$e->url);
$data['status'] = $e->status;
$data['msg'] = $e->msg;
$data['data'] = $e->data;
$data['url'] = $e->url;
return json($data);
}
// 參數驗證錯誤
if ($e instanceof ValidateException) {
return json($e->getMessage());
}
// 其他錯誤交給系統處理
return parent::render($e);
}
protected function analyze($level,$status,$data,$url)
{
$log['status'] = $status;
$log['data'] = $data;
$log['url'] = $url;
$log['error'] = $this->error;
//異常級別
switch (true){
case $level==2:
$log['level']='app_warning';
//self::sendEmail($log) 發送郵件
break;
case $level==3:
$log['level']='app_error';
//self::sendSMS() 發送短信
break;
default:
$log['level']='app_notice';
}
Log::record($log,$log['level']);
return true;
}
protected function getException($e)
{
if($e instanceof \Exception) {
$this->error = [
'name' => get_class($e),
'file' => $e->getFile(),
'line' => $e->getLine(),
'msg' => $e->msg,
];
}
return $this;
}
}
```
當我們手動拋出異常:
```
throw new AppValidateException('這是一個error級別異常',3);
```
我們會在日志文件中找到以下日志記錄:
```
[ 2018-11-30T16:26:44+08:00 ] 127.0.0.1 GET www.xxx.com/index.php/index/index/hello
[ error ] [0]
[ app_error ] array (
'status' => 1,
'data' =>
array (
),
'url' => '',
'error' =>
array (
'name' => 'app\\common\\exception\\AppValidateException',
'file' => 'D:\\wamp\\www\\www.xxx.com\\php\\application\\index\\controller\\Index.php',
'line' => 15,
'msg' => '這是一個error級別異常',
),
'level' => 'app_error',
)
```
ok,異常接管的騷操作就到這了。