1. Exception处理缘由
想必总有过这种情况,你的前端小伙有时收到一个框架自带的报错,一脸懵逼,然后找你,XXXX... 好吧,我们 PHP 虽然开发敏捷,但也要严谨。...于是乎,查询,嗯,得判空;保存,得判断返回的结果。 哇,发现一个方法里要判断好多好多次呀,类似下面这种伪代码:(举个例子,实际中可能不多)
//以下代码写控制器里了
//我要添加一个商品,得先查看该分类是否存在吧
$category = Category::find($category_id);
if (! $category) {
// 返回自定义错误json给前端...
}
//
$product = Product::create(['name' => 'iphone', ...]);
if (! $product) {
// 返回自定义错误json给前端...
}
if (isset($product['...'])) {
// 返回自定义错误json给前端
}
.
.
.
// 对这个才是我们想要的结果
以上放在控制器里本身并无大碍,但是控制器里,只该呈现大体逻辑代码,查询数据库应写在Model不是么?
是的
Fuck 于是我想了一下该咋办呢 于是有了后面的代码
// 模型里的代码
public static function handleProduct()
{
//... 省略
if (! $category) {
return 1;
}
if (! $production) {
return 2;
}
if (! $others) {
return 3;
}
// .. 后面可能还有
}
...
// 控制器里的代码
$result = Product::handleProduct(..);
switch($result) {
case 1 :
// 处理这种情况的报错
break;
case 2:
// 处理第二种情况的报错
break;
case 3:
// 处理其他情况的报错
break
}
我们公司很多地方都有这种为了严谨一点,不得不写出这种恶心的代码......
很长一段时间,突然看到了一种很好很好解决这个问题的办法了... 于是乎,重要关头来了。
2. 处理异常类
以laravel 框架作为实例,TP5还有其他框架都有的~
- 创建 /app/Exceptions/BaseException.php
namespace App\Exception;
class BaseException extends \Exception
{
/** 自定义http 状态码
* @var int
*/
public $code = 400;
/** 自定义错误类型码
* @var int
*/
public $errCode = 10000;
/** 自定义错误消息
* @var string
*/
public $msg = '';
public function __construct($config = [])
{
if (array_key_exists('code', $config)) {
$this->code = $config['code']
}
if (array_key_exists('errCode', $config)) {
$this->code = $config['errCode']
}
if (array_key_exists('msg', $config)) {
$this->code = $config['msg']
}
}
}
// 这个类主要用于作为错误基类,主要为了可以在throw new MyException($config),可以自定义错误内容。
- 打开 /app/Exceptions/Handle.php
// 这里关注在render方法,可以重写覆盖render方法
public function render($request, Exception $exception)
{
// 首先我们得判断 抛出的Exception 是不是继承我们的基类BaesException
if ($exception instanceof BaseException) {
return Response()->json([
'errCode' => $exception->errCode,
'msg' => $exception->msg
], $exception->code);
}
// 如果不是我们想要定义的错误 不在生产环境的话,还是返回错误页面
if (env('APP_DEBUG')) {
parent::render();
}
// 生产环境
return Response()->json([
'errCode' => 999,
'msg' => '服务器内部错误'
], 501);
}
有了这个,我们再写代码就舒服啦~ 如下
// 某个模型
public function ManyErrorMethod()
{
if (! $category) {
throw new CategoryNotFoundException();
}
if (! $product) {
throw new SaveDataErrorException(['errCode' => 12001, 'msg' => '保存商品失败'])
}
}
3. 处理验证类
有了以上的异常类,在验证类这一块可以说是非常爽的~
- 创建 /app/Validates/BaseValidate.php
class BaseValidate
{
/** 规则
* @var int
*/
protected $rule = [];
/** 根据规则返回的错误消息
* @var int
*/
protected message = [];
// 以上都是和laravel 自带的 make:request 差不多的。
public functio check($params = [])
{
// 如果传了,那么就只验证传过来的参数,否则验证所有参数。
$params = empty($params) ? request()->all() : $params;
$validate = Validator::make($param, $this->rule);
// 如果验证没通过
if ($validate->fails()) {
// 抛出自定义的异常,记得继承上面说的 BaseException
throw new CustomException([
'code' => '400',
'errCode' => $validate->messages()->first()
]);
}
return;
}
// 差不多就这样完成了,不过有个问题,就是不同的参数错误,应该对应不同的错误码。
// 所以,可以更改一下上面 错误类的 render 方法
}
- 更改 /app/Exception/Handle.php
public function render($request, Exception $exception)
{
// 首先我们得判断 抛出的Exception 是不是继承我们的基类BaesException
if ($exception instanceof BaseException) {
// 自定义一个错误类Error 里面有一个错误的属性
// public static $errCodes = ['501' => '操作数据错误']
// 然后还有个 根据错误码, 获取错误信息的方法 getErrorMsg
$msg = Error::getErrorMsg($exception->errCode);
return response()->json([
'code' => $exception->code,
'errCode' => $errCode,
'msg' => $msg
]);
}
// 如果不是我们想要定义的错误 不在生产环境的话,还是返回错误页面
if (env('APP_DEBUG')) {
parent::render();
}
// 生产环境
return Response()->json([
'errCode' => 999,
'msg' => '服务器内部错误'
], 501);
}
- 最后创建Validate类继承BaseValidate
// createDeviceValidate.php
class CreateDeviceValidate extends BaseValidate
{
// 还是填以前的规则
protected $rule = [
'gateway_sn' => 'required|exists:gateways,sn',
'sn' => 'required|unique:devices,sn',
'type' => 'required|positiveIntger',
'mac' => 'required'
];
// 信息填错误码就好了~
protected $message = [
'gateway_sn.required' => '213001',
'gateway_sn.exists' => '213005',
'sn.required' => '214001',
'sn.unique' => '214002',
'type.required' => '214005',
'type.positive_intger' => '214006',
'mac.required' => '214007'
];
}
- 最后控制器的写法
public function create(CreateDeviceValidate $createDeviceValidate)
{
// 就这样check咯 简单
$createDeviceValidate->check();
}