普通处理接口有时报错返回的信息,显得不专业且体验极差,特别是对使用的用户而言。今天整理下ThinkPHP8(ThinkPHP6也适用)应用异常处理文档。
(附上一张未处理的应用异常图)
一、在PHP中,可以使用异常处理来处理代码中出现的错误或者不可预见的情况
- 提高程序稳定性:通过捕获和处理异常,可以确保应用程序在遇到问题时不会崩溃,而是能够继续执行。
- 错误报告:异常处理允许记录和报告错误信息,便于开发人员了解和解决问题。
- 用户友好:适当的异常处理可以提供更友好的用户界面,避免向用户显示晦涩的错误消息。
- 资源管理:异常处理还可以用于释放资源,如文件、数据库连接和网络连接,确保它们在不再需要时被正确关闭。
二、异常处理类
在项目的应用目录下(app)存在着一个 ExceptionHandle.php 文件 可以在这里对应用的异常进行处理。
<?php
namespace app;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\exception\Handle;
use think\exception\HttpException;
use think\exception\HttpResponseException;
use think\exception\InvalidArgumentException;
use think\exception\ValidateException;
use think\Response;
use Throwable;
use ParseError; // 语法错误
use think\db\exception\PDOException; // 数据库连接错误
use think\db\exception\DbException; // 数据库模型访问错误,比如方法不存在
use think\exception\RouteNotFoundException;
use think\exception\ClassNotFoundException;
/**
* 应用异常处理类
*/
class ExceptionHandle extends Handle
{
/**
* 不需要记录信息(日志)的异常类列表
* @var array
*/
protected $ignoreReport = [
HttpException::class,
HttpResponseException::class,
ModelNotFoundException::class,
DataNotFoundException::class,
ValidateException::class,
];
/**
* 记录异常信息(包括日志或者其它方式记录)
*
* @access public
* @param Throwable $exception
* @return void
*/
public function report(Throwable $exception): void
{
// 使用内置的方式记录异常日志
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* @access public
* @param \think\Request $request
* @param Throwable $e
* @return Response
*/
public function render($request, Throwable $e): Response
{
// ①请求异常
if ($e instanceof HttpException && $request->isAjax()) {
return self::result($e->getMessage(), $e->getStatusCode());
}
// ②错误的数据类型 或 缺失参数 413
if ($e instanceof InvalidArgumentException ) {
$fileUrlArr = explode(DIRECTORY_SEPARATOR, $e->getFile());
$data = [
'err_msg' => $e->getMessage(),
'file' => $fileUrlArr[count($fileUrlArr) - 1],
'line' => $e->getLine()
];
return self::result('参数错误',$data,413);
}
// ③参数验证错误 422
if ($e instanceof ValidateException) {
return self::result('参数验证不通过',$e->getError(), 422);
}
// 2.方法、资源未匹配到 404
if(($e instanceof ClassNotFoundException || $e instanceof RouteNotFoundException) || ($e instanceof HttpException && $e->getStatusCode()==404)){
$data = [
'err_msg' => $e -> getMessage(),
];
return self::result('方法或资源未找到,请检查',$data, 404);
}
// ④语法错误
if ($e instanceof ParseError) {
$fileUrlArr = explode(DIRECTORY_SEPARATOR, $e->getFile());
$data = [
'err_msg' => $e->getMessage(),
'file' => $fileUrlArr[count($fileUrlArr) - 1],
'line' => $e->getLine()
];
return self::result('服务器异常-语法错误',$data,411);
}
// ⑤数据库错误
if ($e instanceof PDOException || $e instanceof DbException) {
$fileUrlArr = explode(DIRECTORY_SEPARATOR, $e->getFile());
$data = [
'err_msg' => $e->getMessage(),
'file' => $fileUrlArr[count($fileUrlArr) - 1],
'line' => $e->getLine()
];
return self::result('服务器异常-数据库错误',$data,412);
}
// apidoc的异常未被正确响应
if ($e instanceof \hg\apidoc\exception\HttpException) {
$data = [
'err_msg' => $e->getMessage(),
'line' => $e->getLine()
];
return self::result('参数错误',$data, $e->getCode());
}
// 其他错误交给系统处理
return parent::render($request, $e);
}
/**
* 统一返回处理
*/
public function result(string $msg = 'error', array $data = [], int $code = 200, string $type = 'json'): Response
{
$result = [
"code" => $code,
"msg" => $msg,
"data" => $data
];
// 调用Response的create方法,指定code可以改变请求的返回状态码
return Response::create($result, $type)->code($code);
}
}
应用异常捕捉后处理结果如下: