AOP思想的统一异常处理

在未接触AOP思想的时候,我们会这样来处理我们的异常信息,直接return异常信息"XXX异常",或者直接抛出一个系统或者框架自带的Exception返回给接口的调用方,但是在接触AOP思想了,这种方式就不可取了,并且不便于扩展。最近在做小程序后端,我拿自己的一个例子来举例(这里用的是thinkphp5框架):

设计图:

AOP思想的统一异常处理

1.创建自己的基类BaseException.php

<?php
namespace app\lib\exception;

use think\Exception;

/**
 * Class BaseException
 * 异常类的基类-自定义异常类
 */
class BaseException extends Exception
{
    public $code = 400;
    public $msg = '异常错误';
    public $errorCode = 999;
    /**
     * 构造函数,接收一个关联数组
     * @param array $params 关联数组只应包含code、msg和errorCode,且不应该是空值
     */
    public function __construct($params = [])
    {
        if (!is_array($params)) {
            return;
        }
        if (array_key_exists('code', $params)) {
            $this->code = $params['code'];
        }
        if (array_key_exists('msg', $params)) {
            $this->msg = $params['msg'];
        }
        if (array_key_exists('errorCode', $params)) {
            $this->errorCode = $params['errorCode'];
        }
    }
}

2.创建ExceptionHandler.php重写框架的抛出异常的render方法

<?php

namespace app\lib\exception;

use think\exception\Handle;
use think\Log;
use think\Exception;

/*
 * 重写Handle的render方法,实现自定义异常消息
 */
class ExceptionHandler extends Handle
{
    private $code;
    private $msg;
    private $errorCode;

    public function render(\Exception $e)
    {
        if ($e instanceof BaseException) {
            //如果是自定义异常,则控制http状态码,不需要记录日志
            //因为这些通常是因为客户端传递参数错误或者是用户请求造成的异常c
            //不应当记录日志
            $this->code = $e->code;
            $this->msg = $e->msg;
            $this->errorCode = $e->errorCode;
        } else {
            // 如果是服务器未处理的异常,将http状态码设置为500,并记录日志
            if (config('app_debug')) {
                // 调试状态下需要显示TP默认的异常页面,因为TP的默认页面
                // 很容易看出问题
                return parent::render($e);
            }
            $this->code = 500;
            $this->msg = 'sorry,we make a mistake. (^o^)Y';
            $this->errorCode = 999;
            $this->recordErrorLog($e);
        }
        $result = [
            'msg' => $this->msg,
            'error_code' => $this->errorCode,
            'request_url' => request()->url()
        ];

        return json($result, $this->code);
    }
    /*
     * 将异常写入日志
     */
    private function recordErrorLog(\Exception $e)
    {
        Log::init([
            'type' => 'File',
            'path' => LOG_PATH,
            'level' => ['error ']
        ]);
        Log::record($e->getMessage(), 'error');
    }
}

3.创建ParameterException.php参数异常类来检测交互数据

<?php

namespace app\lib\exception;

/**
 * Class ParameterException
 * 通用参数类异常错误
 */
class ParameterException extends BaseException
{
    public $code = 400;
    public $errorCode = 10000;
    public $msg = "参数异常错误";
}

4.可以创建别的异常类来进行自定义异常信息,和参数异常类格式保持一致 例如:OrderException.php(订单异常类)

<?php
namespace app\lib\exception;

/**
 * 订单错误抛出此异常
 */
class OrderException extends BaseException
{
    public $code = 404;
    public $msg = '订单不存在,请检查ID';
    public $errorCode = 80000;
}

通过这种方式统一管理自己的异常可以实现更好的扩展,同时也可以在构造函数中传入自己想要的参数来修改异常类中的属性值,比如错误信息msg,错误码errorCode等。