tp5.1可以自定义异常接管,具体参见文档[异常处理接管](https://ihavenolimitations.xyz/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,异常接管的骚操作就到这了。