您好,欢迎访问一九零五行业门户网

如何优雅的使用异常

老子曰:程序开发时,有 80% 的代码在处理各种异常。
由于php实在是太过于灵活简单,很多phper对异常的处理其实不太感冒,于是乎,我们会经常看到
die(xxx);
exit(xxx);
这样的异常处理,但这类异常对于项目的稳定性却很不友好,主要有以下几点问题:
1:粗暴的打断正常的业务流。
2:调试非常因难。
3:灵活度太差
那我们展开来看这三个问题:
1:现代的框架,大都有一个标准的处理流程:
_before();  //前置控制器,可以做一个数据的初始化
run();      //业务逻辑的处理
_after();   //后置控制器,在处理完业务,有机会进行收尾(比如回收资源,统一打日志等)。
但如果的 业务逻辑处理里(run)直接用 exit, die这类函数会直接退出php当前脚本的执行,从而跳过_after(),这显然不符合正常的逻辑。
2:笔者曾经有个经历,打开某个页面,突然白屏,经过一翻苦苦的debug,终于在某处发现了一个孤零零的exit,没有任何提示,碰到这样的代码,对于调试者来说,就是个噩梦。
3:现在已经不再是pc互联网的时候,移动互联网比例已大幅增加,这时,我们往往是输出一个接口,如果直接碰到exit, die这类输出可能直接导致客户端崩溃。
那正确的使用方式是什么?
没错,就是php自带的exception, php自带的exception非常的强大而且友好,可能由于历史原因,很多人没有习惯使用它。
所以,针对第一个问题,我们在进行框架设计的时候,就可以这么处理:
try {
$ctrl->_before();
$ctrl->$method();
$ctrl->_after();
} catch (\exception $e) {
$ctrl->_atfer(); //让_after在异常后也能正常执行
throw $e;        //再抛出异常
}
抛出异常之后, 通过exception类自带的 gettrace()方法,可以获得调用栈,这样就能很方便的进行调试。
最后可以通过set_exception_handler自定义异常处理,最终输出正确的数据格式。
帖上一小段我常用的异常处理代码。
假定我们的api代码约定:
{
code: 0,   //非0表示异常
msg:  ,  //提示信息,非0时有值
data: {}   //code=0时的业务数据,
}
自定义异常处理类
realcode = $code;
parent::__construct($message, $code);
}
public static function exceptionhandler(\exception $exception)
{
$model = zformater::exception($exception);            //格式化异常
log::info([\var_export($model, true)], 'exception');  //异常写日志
$info = array();
if(property_exists($exception, 'realcode')) {
$codearr = explode('_', $exception->realcode);
if(count($codearr) > 1) {
$model['code'] = intval($codearr[0]);
$model['msg'] = $codearr[1];
}
}
if ($config['debug_mode']) {                          //调式模式,输出调用栈
$info['debug'] = $model;
}
$info['msg'] = $model['message'];
$info['ret'] = empty($model['code']) ? -1 : $model['code'];
if(request::isajax()) {                              //ajax请求,json串输出
request::setviewmode('json');
}
if('php' == request::getviewmode()) {               //页面请求,统一的异常页面展示
if ($config['debug_mode']) {
request::settplfile('public/exception.php');
} else {
request::settplfile('public/error.php');
}
}
response::display($info);
}
realcode对应的定义:
class error
{
const def_msg = '系统异常';
//系统级异常码
const param_error = '1_参数异常';
const need_login =  '2_需要登录';
const user_error =  '3_用户名不存在';
const pass_error =  '4_密码异常';
}
然后通过set_exception_handler(myexception::exceptionhandler); 进行自定义异常处理后,我们在业务层,碰到异常的逻辑,就可以统一的、愉快的进行下面这样的异常抛出了:
throw new myexception('param xxx error', error::param_error);
那么最终输出的api将会是:
{
code: 1,
msg:  参数异常
}
这样就可以和exit, die 说再见了。
ps: 以上代码大都取自zphp框架,详细可参考zphp框架: https://github.com/shenzhe/zphp
--------------伟大的分割线----------------
php饭米粒(phpfamily) 由一群靠谱的人建立,愿为phper带来一些值得细细品味的精神食粮!
本文由 桶哥 原创,转载请注明本来源信息和以下的二维码(长按可识别二维码关注):
其它类似信息

推荐信息