如何优雅的设计PHP异常

前言

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

异常的类别

PHP7异常做了很多变动,异常类 Exception 和错误类 Error 都实现了 Throwable 接口

结构如下:

  • Throwable

    • Error

      • ArithmeticError

        • DivisionByZeroError
      • AssertionError
      • ParseError
      • TypeError

        • ArgumentCountError
    • Exception

      • ClosedGeneratorException
      • DOMException
      • ErrorException
      • IntlException
      • LogicException

        • BadFunctionCallException

          • 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();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值