PHP中的异常的独特性,即PHP中的异常不同于主流语言C++、java中的异常。在Java中,异常是唯一的错误报告方式,而在PHP中却不是这样,而是把所有不正常的情况都视作了错误进行处理。这两种语言对异常和错误的界定存在分歧。什么是异常什么是错误,两种语言的设计者存在不同的观点。
是程序在运行中出现不符合预期的情况及与正常流程不同的状况。一种不正常的情况,按照正常逻辑本不该出的错误,但仍然会出现的错误,这是属于逻辑和业务流程的错误,而不是编译或者语法上的错误。
是属于php脚本自身的问题,大部分情况是由错误的语法,服务器环境导致,使得编译器无法通过检查,甚至无法运行的情况。warning、notice都是错误,只是他们的级别不同而已,并且错误是不能被try-catch捕获的。
在PHP中遇到任何自身错误都会触发一个错误,而不是抛出异常。PHP一旦遇到非正常代码,通常都会触发错误,而不是抛出异常。因此,如果想要使用异常处理不可预料的问题,是办不到的。
composer require tinywan/exception-handler
config/exception.php
return [
// 这里配置异常处理类
'' => \Tinywan\ExceptionHandler\Handler::class,
];
异常接管
/plugin/admin/config/exception.php
return [
'' => \Tinywan\ExceptionHandler\Handler::class,
];
接口不存在路由处理
/plugin/admin/config/route.php
Route::fallback(function () {
throw new \Tinywan\ExceptionHandler\Exception\RouteNotFoundException();
}, 'admin');
请求参数错误
use support\Request;
use support\Response;
use Tinywan\ExceptionHandler\Exception\BadRequestHttpException;
class Token{
public function issueToken(Request $request): Response
{
$params = $request->post();
if (empty($params)) {
throw new BadRequestHttpException('账号或密码不能为空');
}
}
}
以上异常抛出错误信息,如下格式:
HTTP/1.1 400 Bad Request
Content-Type: application/json;charset=utf-8
{
"code": 0,
"msg": "账号或密码不能为空",
"data": {},
}
所有返回的异常信息将以json格式返回,以上为
返回简略的异常信息
所有的异常错误处理器根据配置文件 config/app.php
中debug
的值来调整错误显示, 当debug
值为true
(表示在调试模式), 错误处理器会显示异常以及详细的函数调用栈和源代码行数来帮助调试,将返回详细的异常信息。当debug
值为false
,只有错误信息会被显示以防止应用的敏感信息泄漏,将返回简略的异常信息。
返回详细的异常信息
HTTP/1.1 400 Bad Request
Content-Type: application/json;charset=utf-8
{
"code": 0,
"msg": "password不允许为空",
"data": {
"request_url": "POST //127.0.0.1:8888/oauth/issue-token",
"timestamp": "2022-03-06 15:19:12",
"client_ip": "172.18.0.1",
"request_param": {
"username": "webman"
},
"error_message": "password不允许为空",
"error_trace": "#0 /var/www/webman-admin/app/functions.php(68): Tinywan\\Validate\\Validate->check(Array)\n#1 /var/www/webman-admin/app/controller/Authentication.php(25): ..."
}
}
假设自定义一个:405 Method Not Allowed
(表示:请求行中指定的请求方法不能被用于请求相应的资源)
自定义异常类只需要继承Tinywan\ExceptionHandler\Exception\BaseException
类即可
<?php
declare(strict_types=1);
namespace support\exception;
use Tinywan\ExceptionHandler\Exception\BaseException;
class MethodNotAllowedException extends BaseException
{
/**
* @var int
*/
public $statusCode = 405;
/**
* @var string
*/
public $errorMessage = '请求行中指定的请求方法不能被用于请求相应的资源';
}
use support\Request;
use support\Response;
use support\exception\MethodNotAllowedException;
class Token{
public function issueToken(Request $request): Response
{
$params = $request->post();
if (empty($params)) {
throw new MethodNotAllowedException();
}
}
}
使用postman请求截图
JwtTokenException
ValidateException
更多:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
只支持修改body
的三个字段的key值。必须保持顺序是:
使用场景
HTTP状态码
并不是 429
,而是 200
或者其他body
不是 {"code":0,"msg":"Too Many Requests"}
,而是 {"error_code":200,"message":"Too Many Requests"}
等其他内容编辑 config/plugin/tinywan/exception-handler/app.php
文件的 status
HTTP 状态码
body
返回内容编辑 config/plugin/tinywan/exception-handler/app.php
文件的 body
的字段
「默认选项是」
{
"code": 0,
"msg": "Too Many Requests",
"data": null
}
自定义选项参考一
1、假设status
HTTP 状态码设置为 200
2、假设body
的数组设为为
'body' => [
'error_code' => 200,
'message' => '请求太多请稍后重试'
]
则响应内容为
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
{
"error_code": 200,
"message": "请求太多请稍后重试"
}
其他的可以根据自身业务自定义即可
当项目需要自定义情况比较多的时候,很可能需要扩展 Handler,此时可以继承 Tinywan\ExceptionHandler\Handler
然后修改对应方法即可。
使用场景
xml
,而不是json格式,只需要覆盖buildResponse
方法solveExtraException
triggerNotifyEvent
自定义异常 ErrorHandler
namespace support;
use Illuminate\Validation\ValidationException;
use Tinywan\ExceptionHandler\Handler;
use Webman\Http\Response;
class ErrorHandler extends Handler
{
/**
* @inheritDoc
*/
protected function solveExtraException(\Throwable $e): void
{
// 当前项目下的异常扩展
if ($e instanceof ValidationException) {
$this->errorMessage = $e->validator->errors()->first();
$this->errorCode = 422;
return;
}
parent::solveExtraException($e);
}
/**
* @inheritDoc
*/
protected function triggerNotifyEvent(\Throwable $e): void
{
// ... 这里省略触发其他错误推送渠道
parent::triggerNotifyEvent($e);
}
/**
* @inheritDoc
*/
protected function buildResponse(): Response
{
// 构造自己项目下的响应
return json([
'code' => $this->statusCode, // 使用 statusCode 作为 code 返回
'msg' => $this->errorMessage,
'data' => $this->responseData,
]);
}
}
视频:https://www.bilibili.com/video/BV1bP4y1g7AL