05.异常统一处理
php
异常处理以前是这样的。
try {
// may be thrwo exception
// ... do sth
} catch(\Exception $e) {
// catch the exception
// ... do sth
} finally {
// to run ,don`t care of any gexception
// ... do sth
}
tip
以上有什么问吗? 有。太他妈烦了,我要有10个地方可能抛异常,10个地方这样整也不好, 太
烦了。 那能不能代码复用,统一处理,还可以做下日志记录啥的?嘿嘿__!行的! 既然要玩那就做个正经些的demo
。
上composer
.
1创建demo
- 1.1
make demo && cd demo
; 创建demo项目,并进入项目根目录 - 1.2
composer init
;或许要输入姓名和邮箱其它啥也不用管,一路开车enter
. - 1.3 修改
composer.json
,注册本地项目命名空间; 新建字段autoload
,配置自动引入目录app
;
{
"name": "nginx/demo",
"authors": [
{
"name": "wuchuheng",
"email": "wuchuheng@163.com"
}
],
"autoload": {
"psr-4":{
"app\\": "app/"
}
},
"require": {}
}
composer update
更新下
这样为只要载入vender/autoload.php
,就根据命名空间来加载类。
1.2 创建入口文件和异常处理器
1.2.1在根据目录新建入口文件start.php
/**
* 入口文件
*
* @filename start.php
* @author wuchuheng<wuchuheng@163.com>
* @date 2019/07/28
*/
require_once __DIR__ . "/vendor/autoload.php";
// 指定render方法来抛出异常
set_exception_handler([(new \app\exception\HandlerException()), 'render']);
//抛一个异常试试
throw new \app\exception\HandlerException('hello');
1.2.2 新建处理器文件app\exception\HandlerException.php
/**
* 异常处理器Handler
*
* @filename HandlerException.php
* @author wuchuheng <wuchuheng@163.com>
* @date 2019/07/28
*/
namespace app\exception;
class HandlerException extends \Exception
{
/**
* 异常抛出
*
*/
public function render($e)
{
echo $e->getMessage();
}
}
行运结果:
到了这里就已经达到我们的期望,只要在入口文件指定异常的处理位置,那么全局的异常处理
将统一到指定的方法处理,统一输出,如是rest API
那就输出json
, web
就html
文本,
cli模式
等等,是不是不用写很多?
2 进一步封装
tip
异常很多种,常见有验证异常服务器异常等情况发生。所以要把这些异常写成一个个可复用的类
来简化信息系统的简化。哪种情况的异常就抛出哪个,大大提高代码的可读性.我以下我就根据
rest API
接口模式来撸下代码。
2.1 创建rest API 异常基类
新建文件 app/excetpion/RestBaseException.php
/**
* Rest API 异常基类
*
* @filename RestBaseException.php
* @author wuchuheng <wuchuheng@163.com>
* @date 2019/07/28
*/
namespace app\exception;
class RestBaseException extends\Exception
{
public $code = 404; // http 状态码
public $errorCode = 4000; // 接口错误码
public $msg = ''; // 错误详情
/**
* 格式化参数
*
*/
public function __construct(array $args = [])
{
if (array_key_exists('code', $args)) {
$this->code = $args['code'];
}
if (array_key_exists('errorCode', $args)) {
$this->errorCode = $args['errorCode'];
}
if (array_key_exists('msg', $args)) {
$this->msg = $args['msg'];
}
}
}
2.2 验证异常类
/**
* 验证异常类
*
* @filename ValidateException.php
* @author wuchuheng <wuchuheng@163.com>
* @date 2019/07/28
*/
namespace app\exception;
use \app\exception\RestBaseException;
class ValidateException extends RestBaseException
{
public $code = 404;
public $errorCode = 4000;
public $msg = '验证异常';
}
2.3 修改异常处理器类
/**
* 异常处理器Handler
*
* @filename HandlerException.php
* @author wuchuheng <wuchuheng@163.com>
* @date 2019/07/28
*/
namespace app\exception;
use \app\exception\RestBaseException;
class HandlerException extends \Exception
{
/**
* 异常抛出
*
*/
public function render($e)
{
// RestApi 异常处理
if ($e instanceof RestBaseException) {
echo '抛出的是Rest API扔异常';
echo '错误码是:' . $e->errroCode . PHP_EOL;
echo '错误信息是:' . $e->msg. PHP_EOL;
echo '状态码是:' . $e->code. PHP_EOL;
}
}
}
2.4 现在可以抛出了
/**
* 入口文件
*
* @filename start.php
* @author wuchuheng<wuchuheng@163.com>
* @date 2019/07/28
*/
require_once __DIR__ . "/vendor/autoload.php";
// 指定render方法来抛出异常
set_exception_handler([(new \app\exception\HandlerException()), 'render']);
//抛一个异常试试
/* throw new \app\exception\HandlerException('hello'); */
throw new \app\exception\ValidateException([
'code'=> 74110, //气死110
'errorCode'=> 111,
'msg'=> '这里是首页,正在抛出一个验证异常,有人吗?',
]);
// 什么也不写就使用默认的定义好的参数抛出
throw new \app\exception\ValidateException();
运行结果:
整体的思路是这样的,首先,不管理是抛出的是什么类,这个类必须是Exception
的子类。
而在入口文件指定好异常类,已经指定好异常的触发处理方法。然后,抛过去的类,在由于是
RestBaseException
的子类,判断成立,就进入到里面了。
3 扩展性
这里要说下异常的扩展性,扩展是可以横向的,文中只是列出一种。可以根据开发的情况,
如是html
的异常那就,新增一个HtmlBaseException
类,让html
超文本的所以异常类
根据上面的例子来扩容,并在异常处理器添加下判断并把处理业务写进去就行了。
所以整体上来看,异常处理已经听可以划分为一个功能模块来看待。
如 可以这么写:
/**
* 异常抛出
*
*/
public function render($e)
{
// RestApi 异常处理
if ($e instanceof RestBaseException) {
echo '抛出的是Rest API扔异常';
echo '错误码是:' . $e->errorCode . PHP_EOL;
echo '错误信息是:' . $e->msg. PHP_EOL;
echo 'http状态码是:' . $e->code. PHP_EOL;
//....
// log 做下日志处理啥的
// return json 返回数据 json
}
// http 异常正理
//if ($e instanceof HttpBaseException)
// 系统异常正理
//if ($e instanceof SystemBaseException)
}