浅谈 PHP 中异常类的使用
为什么要使用异常类
-
优化代码的可读性
在没有异常的时候我们在编写函数时往往会出现以下情况:
function doSomething(){ if(something error){ return false; } ... do something } //调用 $result = doSomething(); if(!$result){ echo "something goes error"; }
如果使用异常则可以这么写:
function doSomething(){ if(something error){ throw new SomethingException('something error'); } ... do something } //调用 try{ doSomething(); }catch(SomethingException $e){ echo "something goes error"; }
无论时调用层面还是函数本身层面,抛出异常的可读性比返回
false
的可读性要更高,因为我们能够一眼就看出来哪些代码是异常时运行的,哪些时正常时运行的。 -
更加符合语义化
异常类往往都有自己的名字,在函数调用层面,即使不进入函数内部也能够通过异常名来判断调用函数会伴有哪些异常,如果函数没有异常,返回的是
false
或true
,这会让函数的调用者非常头痛,因为你永远不知道这个函数调用什么时候是异常的,只能通过返回值判断,一个函数如果有多种异常情况,通过返回值判断就会在调用层面生成多个if
,如果使用了异常类,调用层能够轻松的分别catch
不同的异常来进行处理。// 调用方无法从外部得知时哪里出了问题,因为只返回了 false function checkoutOrder($orderNumber){ $orderModel = OrderModel::query()->where('order_number',$orderNumber)->first(); if(!$orderModel){ return false; } $payResut = PayService::pay($orderModel); if(!$payResut){ return false; } }
为每种程序异常命名:
function checkoutOrder($orderNumber){ $orderModel = OrderModel::query()->where('order_number',$orderNumber)->first(); if(!$orderModel){ throw new OrderNotFoundException($orderNumber); } $payResut = PayService::pay($orderModel); if(!$payResut){ throw new PaymentException(); // 这个异常应该上面的 PayService 中抛出,为了更清晰就写在这 } } // 调用 try{ checkoutOrder('ORDER00001'); }catch(OrderNotFoundException $e){ return response('订单不存在:'.$e->getMessage(),404); }catch(PaymentException $e){ return response('支付失败:'.$e->getMessage(),500); }
在 Laravel 中使用异常类
-
Laravel 异常处理流程:
注:如果在控制器中
catch
最底层的\Exception
,异常就不会走到Handler
里面,未被catch
掉的\Exception
都会记录在storage/logs/laravel.log
中,所以在控制器中 catch 异常要考虑清楚,否则可能在日志文件中查询不到错误原因。-
使用
Handler
做项目错误告警在
app/Exceptions/Handler.php
中根据异常名、紧急程度调用第三方通知工具(钉钉、邮件等)通知项目错误。public function report(Exception $exception){ if ($this->shouldntReport($exception)) { return; } // 如果异常类中存在 report 方法,就使用自身的 if (method_exists($exception, 'report')) { return $exception->report(); } $msg = "系统异常:" . $exception->getMessage(); $msg .= "\n文件:" . $exception->getFile(); $msg .= "\n行号:" . $exception->getLine(); $msg .= "\n参数:" . json_encode(['form_params' => request()->all()]); DingService::sendWarning($msg); parent::report($exception); }
-
在
render
方法根据异常名返回不同的客户端响应:
public function render($request, Exception $exception) { if ($exception instanceof OrderException) { return $this->handleOrderException($exception, $request); } if ($exception instanceof PaymentException) { return $this->handlePaymentException($exception, $request); } return parent::render($request, $exception); }
更多详细说明可查看 Laravel--错误处理
-
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: