如何优雅的设计PHP异常

前言

刚开始接触PHP的时候没有意识到异常的重要性,有时候出问题很难精确的找到问题点,正确的处理异常也是一门学问php

异常的类别

PHP7异常作了不少变更,异常类 Exception 和错误类 Error 都实现了 Throwable 接口前端

结构以下:json

  • Throwable后端

    • Errorrestful

      • ArithmeticErrorapp

        • DivisionByZeroError
      • AssertionError
      • ParseError
      • TypeError框架

        • ArgumentCountError
    • Exception前后端分离

      • ClosedGeneratorException
      • DOMException
      • ErrorException
      • IntlException
      • LogicExceptionui

        • BadFunctionCallExceptionthis

          • BadMethodCallException
        • DomainException
        • InvalidArgumentException
        • LengthException
        • OutOfRangeException
      • PharException
      • ReflectionException
      • RuntimeException

        • OutOfBoundsException
        • OverflowException
        • PDOException
        • RangeException
        • UnderflowException
        • UnexpectedValueException
      • SodiumException

何时才须要抛异常

这个一切从实际出发,若是你以为你的代码可能会出现问题,就能够进行抛出异常

如何捕获异常

PHP中使用 try...catch...finally 捕获异常

public function test()
{
    try {
        //可能出错的代码逻辑
    } catch (\Exception $e) {
        echo $e->getMessage();
    } finally {
        //todo
    }
}

若是不肯定出现异常仍是错误,能够直接捕获 Throwable 异常

public function test()
{
    try {
        //可能出错的代码逻辑
    } catch (\Throwable $e) {
        echo $e->getMessage();
    } finally {
        //todo
    }
}

业务场景实战

如今的项目不少都是先后端分离、restful风格接口的设计进行开发。如今我就用tp5框架来进行实战下在实际业务中是如何优雅的使用异常的

场景描述

选择一个比较简单的业务场景,以登陆模块为例,用户在移动端进行登陆时,须要进行登陆,注册,忘记密码,获取手机验证码等接口。

构建约束条件

登陆

入参:

  • 用户手机号
  • 用户密码
  • 手机验证码

约束:

  • 用户手机号不能为空,格式正确,且此用户确实是存在的
  • 密码不能为空,密码格式正确
  • 手机验证码不能为空,且是在有效期内的

注册

入参:

  • 用户手机号
  • 用户密码
  • 密码二次确认
  • 手机验证码

约束:

  • 用户手机号不能为空,格式正确,且此用户确实是新用户,系统不存在此用户信息
  • 密码不能为空,密码格式正确
  • 二次密码要跟密码同样
  • 手机验证码不能为空,且是在有效期内的

忘记密码:

入参:

  • 用户手机号
  • 用户新密码
  • 密码二次确认
  • 手机验证码

约束:

  • 用户手机号不能为空,格式正确,且此用户确实是存在的
  • 密码不能为空,密码格式正确
  • 二次密码要跟密码同样
  • 手机验证码不能为空,且是在有效期内的

获取手机验证码

入参:

  • 用户手机号

约束:

  • 用户手机号不能为空,格式正确
  • 一分钟内只能获取一次

自定义tp5异常

建立异常处理Handle类

# application\lib\exception\ExceptionHandle

namespace application\lib\exception;

use Exception;
use think\exception\Handle;

class ExceptionHandle extends Handle
{
    /**
     * @var $httpStatusCode http状态码
     */
    private $httpStatusCode;
    
    /**
     * @var $msg 错误信息
     */
    private $msg;
     
    /**
     * @var $code 错误码
     */
    private $code;

    # 自定义错误异常须要重写tp5父类的这个render方法
    public function render(Exception $e)
    {
        if ($e instanceof BaseException) {
            # 自定义异常
            $this->httpStatusCode = $e->httpStatusCode;
            $this->msg = $e->msg;
            $this->code = $e->code;
        } else {
            # 系统异常
            //TODO记录错误日志
            return parent::render($e)
        }
        
        $result = [
            'code' => $this->code,
            'msg' => $this->msg
        ];
        # 返回给前端
        return json($result, $this->httpStatusCode);
}

建立基础的异常类

# application\lib\exception\BaseException

namespace application\lib\exception;

use think\Exception;

# 异常类须要继承tp5的异常基类
class BaseException extends Exception
{
    public $httpStatusCode = 401;

    public $msg = 'parameter error';
    
    public $code = 10000;
    
    public function __construct(array $params = [])
    {
        if (array_key_exists('httpStatusCode', $params)) {
            $this->httpStatusCode = $params['httpStatusCode'];
        }
        
        if (array_key_exists('msg', $params)) {
            $this->msg = $params['msg'];
        }
        
        if (array_key_exists('code', $params)) {
            $this->code = $params['code'];
        }
        
    }
}

建立具体异常类

参数错误异常类

namespace app\lib\exception;

class ParameterException extends BaseException
{
    public $httpStatusCode = 200;

    public $msg = 'parameter error';

    public $code = 10000;
}

用户不存在

class UserNotExistsException extends BaseException
{
    public $httpStatusCode = 200;

    public $msg = 'user is not exists';

    public $code = 20000;
}

如何使用

咱们先来看看登陆这个功能

传统处理方法

public function login($phone, $password)
{
    $uid = $this->getUidByPhone($phone);
    if (!$uid) {
        # 进行处理
    }
}

经过异常处理

public function login($phone, $password)
{
    $uid = $this->getUidByPhone($phone);
    if (!$uid) {
        # 抛出异常,返回给前端
        throw new UserNotExistsException();
    }
}
相关文章
相关标签/搜索