前言

刚开始接触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();

}

}

Logo

更多推荐