亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 語言 > PHP > 正文

Laravel核心解讀之異常處理的實踐過程

2024-05-05 00:06:54
字體:
來源:轉載
供稿:網友

前言

異常處理是編程中十分重要但也最容易被人忽視的語言特性,它為開發者提供了處理程序運行時錯誤的機制,對于程序設計來說正確的異常處理能夠防止泄露程序自身細節給用戶,給開發者提供完整的錯誤回溯堆棧,同時也能提高程序的健壯性。

這篇文章我們來簡單梳理一下Laravel中提供的異常處理能力,然后講一些在開發中使用異常處理的實踐,如何使用自定義異常、如何擴展Laravel的異常處理能力。

下面話不多說了,來一起看看詳細的介紹吧

注冊異常Handler

這里又要回到我們說過很多次的Kernel處理請求前的bootstrap階段,在bootstrap階段的Illuminate/Foundation/Bootstrap/HandleExceptions 部分中Laravel設置了系統異常處理行為并注冊了全局的異常處理器:

class HandleExceptions{ public function bootstrap(Application $app) {  $this->app = $app;  error_reporting(-1);  set_error_handler([$this, 'handleError']);  set_exception_handler([$this, 'handleException']);  register_shutdown_function([$this, 'handleShutdown']);  if (! $app->environment('testing')) {   ini_set('display_errors', 'Off');  } }   public function handleError($level, $message, $file = '', $line = 0, $context = []) {  if (error_reporting() & $level) {   throw new ErrorException($message, 0, $level, $file, $line);  } }}

set_exception_handler([$this, 'handleException'])將HandleExceptions的handleException方法注冊為程序的全局處理器方法:

public function handleException($e){ if (! $e instanceof Exception) {  $e = new FatalThrowableError($e); } $this->getExceptionHandler()->report($e); if ($this->app->runningInConsole()) {  $this->renderForConsole($e); } else {  $this->renderHttpResponse($e); }}protected function getExceptionHandler(){ return $this->app->make(ExceptionHandler::class);}// 渲染CLI請求的異常響應protected function renderForConsole(Exception $e){ $this->getExceptionHandler()->renderForConsole(new ConsoleOutput, $e);}// 渲染HTTP請求的異常響應protected function renderHttpResponse(Exception $e){ $this->getExceptionHandler()->render($this->app['request'], $e)->send();}

在處理器里主要通過ExceptionHandler的report方法上報異常、這里是記錄異常到storage/laravel.log文件中,然后根據請求類型渲染異常的響應生成輸出給到客戶端。這里的ExceptionHandler就是/App/Exceptions/Handler類的實例,它是在項目最開始注冊到服務容器中的:

// bootstrap/app.php/*|--------------------------------------------------------------------------| Create The Application|--------------------------------------------------------------------------*/$app = new Illuminate/Foundation/Application( realpath(__DIR__.'/../'));/*|--------------------------------------------------------------------------| Bind Important Interfaces|--------------------------------------------------------------------------*/......$app->singleton( Illuminate/Contracts/Debug/ExceptionHandler::class, App/Exceptions/Handler::class);

這里再順便說一下set_error_handler函數,它的作用是注冊錯誤處理器函數,因為在一些年代久遠的代碼或者類庫中大多是采用PHP那件函數trigger_error函數來拋出錯誤的,異常處理器只能處理Exception不能處理Error,所以為了能夠兼容老類庫通常都會使用set_error_handler注冊全局的錯誤處理器方法,在方法中捕獲到錯誤后將錯誤轉化成異常再重新拋出,這樣項目中所有的代碼沒有被正確執行時都能拋出異常實例了。

/** * Convert PHP errors to ErrorException instances. * * @param int $level * @param string $message * @param string $file * @param int $line * @param array $context * @return void * * @throws /ErrorException */public function handleError($level, $message, $file = '', $line = 0, $context = []){ if (error_reporting() & $level) {  throw new ErrorException($message, 0, $level, $file, $line); }}

常用的Laravel異常實例

Laravel中針對常見的程序異常情況拋出了相應的異常實例,這讓開發者能夠捕獲這些運行時異常并根據自己的需要來做后續處理(比如:在catch中調用另外一個補救方法、記錄異常到日志文件、發送報警郵件、短信)

在這里我列一些開發中常遇到異常,并說明他們是在什么情況下被拋出的,平時編碼中一定要注意在程序里捕獲這些異常做好異常處理才能讓程序更健壯。

  • Illuminate/Database/QueryException Laravel中執行SQL語句發生錯誤時會拋出此異常,它也是使用率最高的異常,用來捕獲SQL執行錯誤,比方執行Update語句時很多人喜歡判斷SQL執行后判斷被修改的行數來判斷UPDATE是否成功,但有的情景里執行的UPDATE語句并沒有修改記錄值,這種情況就沒法通過被修改函數來判斷UPDATE是否成功了,另外在事務執行中如果捕獲到QueryException 可以在catch代碼塊中回滾事務。
  • Illuminate/Database/Eloquent/ModelNotFoundException 通過模型的findOrFail和firstOrFail方法獲取單條記錄時如果沒有找到會拋出這個異常(find和first找不到數據時會返回NULL)。
  • Illuminate/Validation/ValidationException 請求未通過Laravel的FormValidator驗證時會拋出此異常。
  • Illuminate/Auth/Access/AuthorizationException 用戶請求未通過Laravel的策略(Policy)驗證時拋出此異常
  • Symfony/Component/Routing/Exception/MethodNotAllowedException 請求路由時HTTP Method不正確
  • Illuminate/Http/Exceptions/HttpResponseException Laravel的處理HTTP請求不成功時拋出此異常

擴展Laravel的異常處理器

上面說了Laravel把/App/Exceptions/Handler 注冊成功了全局的異常處理器,代碼中沒有被catch到的異常,最后都會被/App/Exceptions/Handler捕獲到,處理器先上報異常記錄到日志文件里然后渲染異常響應再發送響應給客戶端。但是自帶的異常處理器的方法并不好用,很多時候我們想把異常上報到郵件或者是錯誤日志系統中,下面的例子是將異常上報到Sentry系統中,Sentry是一個錯誤收集服務非常好用:

public function report(Exception $exception){ if (app()->bound('sentry') && $this->shouldReport($exception)) {  app('sentry')->captureException($exception); } parent::report($exception);}

還有默認的渲染方法在表單驗證時生成響應的JSON格式往往跟我們項目里統一的JOSN格式不一樣這就需要我們自定義渲染方法的行為。

public function render($request, Exception $exception){ //如果客戶端預期的是JSON響應, 在API請求未通過Validator驗證拋出ValidationException后 //這里來定制返回給客戶端的響應. if ($exception instanceof ValidationException && $request->expectsJson()) {  return $this->error(422, $exception->errors()); } if ($exception instanceof ModelNotFoundException && $request->expectsJson()) {  //捕獲路由模型綁定在數據庫中找不到模型后拋出的NotFoundHttpException  return $this->error(424, 'resource not found.'); } if ($exception instanceof AuthorizationException) {  //捕獲不符合權限時拋出的 AuthorizationException  return $this->error(403, "Permission does not exist."); } return parent::render($request, $exception);}

自定義后,在請求未通過FormValidator驗證時會拋出ValidationException, 之后異常處理器捕獲到異常后會把錯誤提示格式化為項目統一的JSON響應格式并輸出給客戶端。這樣在我們的控制器中就完全省略了判斷表單驗證是否通過如果不通過再輸出錯誤響應給客戶端的邏輯了,將這部分邏輯交給了統一的異常處理器來執行能讓控制器方法瘦身不少。

使用自定義異常

這部分內容其實不是針對Laravel框架自定義異常,在任何項目中都可以應用我這里說的自定義異常。

我見過很多人在Repository或者Service類的方法中會根據不同錯誤返回不同的數組,里面包含著響應的錯誤碼和錯誤信息,這么做當然是可以滿足開發需求的,但是并不能記錄發生異常時的應用的運行時上下文,發生錯誤時沒辦法記錄到上下文信息就非常不利于開發者進行問題定位。

下面的是一個自定義的異常類

namespace App/Exceptions/;use RuntimeException;use Throwable;class UserManageException extends RuntimeException{ /**  * The primitive arguments that triggered this exception  *  * @var array  */ public $primitives; /**  * QueueManageException constructor.  * @param array $primitives  * @param string $message  * @param int $code  * @param Throwable|null $previous  */ public function __construct(array $primitives, $message = "", $code = 0, Throwable $previous = null) {  parent::__construct($message, $code, $previous);  $this->primitives = $primitives; } /**  * get the primitive arguments that triggered this exception  */ public function getPrimitives() {  return $this->primitives; }}

定義完異常類我們就能在代碼邏輯中拋出異常實例了

class UserRepository{  public function updateUserFavorites(User $user, $favoriteData) {  ......  if (!$executionOne) {   throw new UserManageException(func_get_args(), 'Update user favorites error', '501');  }    ......  if (!$executionTwo) {   throw new UserManageException(func_get_args(), 'Another Error', '502');  }    return true; }}class UserController extends ...{ public function updateFavorites(User $user, Request $request) {  .......  $favoriteData = $request->input('favorites');  try {   $this->userRepo->updateUserFavorites($user, $favoritesData);  } catch (UserManageException $ex) {   .......  } }}

除了上面Repository列出的情況更多的時候我們是在捕獲到上面列舉的通用異常后在catch代碼塊中拋出與業務相關的更細化的異常實例方便開發者定位問題,我們將上面的updateUserFavorites 按照這種策略修改一下

public function updateUserFavorites(User $user, $favoriteData){ try {  // database execution    // database execution } catch (QueryException $queryException) {  throw new UserManageException(func_get_args(), 'Error Message', '501' , $queryException); } return true;}

在上面定義UserMangeException類的時候第四個參數$previous是一個實現了Throwable接口類實例,在這種情景下我們因為捕獲到了QueryException的異常實例而拋出了UserManagerException的實例,然后通過這個參數將QueryException實例傳遞給PHP異常的堆棧,這提供給我們回溯整個異常的能力來獲取更多上下文信息,而不是僅僅只是當前拋出的異常實例的上下文信息, 在錯誤收集系統可以使用類似下面的代碼來獲取所有異常的信息。

while($e instanceof /Exception) { echo $e->getMessage(); $e = $e->getPrevious();}

異常處理是PHP非常重要但又容易讓開發者忽略的功能,這篇文章簡單解釋了Laravel內部異常處理的機制以及擴展Laravel異常處理的方式方法。更多的篇幅著重分享了一些異常處理的編程實踐,這些正是我希望每個讀者都能看明白并實踐下去的一些編程習慣,包括之前分享的Interface的應用也是一樣。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VeVb武林網的支持。


注:相關教程知識閱讀請移步到PHP教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美人与性动交a欧美精品| 日韩精品免费观看| 国产欧美日韩精品在线观看| 久久国产精品久久国产精品| 久久精品国产v日韩v亚洲| 九九久久综合网站| 亚洲国产精品99| 51精品国产黑色丝袜高跟鞋| 亚洲桃花岛网站| 国产精品入口免费视频一| 国产精品自产拍在线观看| 国产精品午夜国产小视频| 美女黄色丝袜一区| 日韩国产精品视频| 91在线网站视频| 欧美乱大交做爰xxxⅹ性3| 国产成人精品在线| 成人啪啪免费看| 欧美日韩亚洲精品一区二区三区| 热久久这里只有精品| 日韩美女激情视频| 亚洲天堂男人的天堂| 亚洲男人av在线| 26uuu久久噜噜噜噜| 亚洲国产精品va在看黑人| 欧美一性一乱一交一视频| 日韩av中文字幕在线免费观看| 欧美性猛交xxxx偷拍洗澡| 久久99精品国产99久久6尤物| 亚洲aⅴ男人的天堂在线观看| 26uuu国产精品视频| 欧美激情网站在线观看| 亚洲一区二区三| 亚洲国产精品成人一区二区| 亚洲国产精品99久久| 欧洲成人免费aa| 亚洲欧洲日韩国产| 欧美电影免费观看网站| 亚洲精品乱码久久久久久金桔影视| 欧美成人精品不卡视频在线观看| 日韩最新免费不卡| 久久偷看各类女兵18女厕嘘嘘| 久久久中精品2020中文| 2019中文在线观看| 亚洲综合精品伊人久久| 最近中文字幕mv在线一区二区三区四区| 欧美亚洲国产日韩2020| 久久久久久国产精品三级玉女聊斋| 久久激情视频免费观看| 日韩视频免费在线观看| 精品成人av一区| 亲子乱一区二区三区电影| 亚洲第一中文字幕| 欧美第一黄色网| 国产精品一区二区久久精品| 这里只有精品在线播放| 性夜试看影院91社区| 日本国产欧美一区二区三区| 欧美肥臀大乳一区二区免费视频| 亚洲欧美日韩另类| 色中色综合影院手机版在线观看| 亚洲人成毛片在线播放| 国产成人精品免高潮费视频| 亚洲一区二区三区777| 最近2019中文免费高清视频观看www99| 亚洲欧美在线看| 欧美性猛交xxxx富婆| 欧美亚洲在线观看| 国产偷亚洲偷欧美偷精品| 中文字幕精品www乱入免费视频| 国产精品亚洲аv天堂网| 中文字幕日韩精品在线观看| 55夜色66夜色国产精品视频| 97热精品视频官网| 欧美性xxxx极品高清hd直播| 亚洲第一av网| 日韩av资源在线播放| 亚洲精品国产欧美| 国产精品久久久久久久久久久久久| 亚洲永久免费观看| 午夜精品久久久久久久白皮肤| 亚洲黄页网在线观看| 欧美猛男性生活免费| 欧美日韩精品在线观看| 国产精品久久久久久久久免费| 美日韩精品免费视频| 日韩有码在线播放| 久久久久久久国产精品视频| 日韩美女毛茸茸| 亚洲第一男人天堂| 国产免费观看久久黄| 国产精品视频1区| 精品美女国产在线| 亚洲日本欧美日韩高观看| 日韩亚洲综合在线| 日韩在线视频观看正片免费网站| 欧美日韩精品在线播放| 久久99久久99精品中文字幕| 亚洲欧美激情视频| 国产精品久久久久久久久| 日韩免费av一区二区| 欧美日韩免费网站| 国产精品自产拍在线观看| 欧美国产日韩中文字幕在线| 日韩最新在线视频| 亚洲最大成人免费视频| 国产精品人成电影在线观看| 亚洲日本欧美日韩高观看| 黄色精品在线看| 91免费人成网站在线观看18| 日韩成人在线播放| 成人xvideos免费视频| 夜夜嗨av一区二区三区四区| 免费不卡在线观看av| 欧美大荫蒂xxx| 欧美大片va欧美在线播放| 国产成人av网址| 日韩精品亚洲视频| 欧美激情免费看| 日本国产欧美一区二区三区| 成人网在线视频| 欧美午夜视频一区二区| 亚洲丝袜在线视频| 欧美—级a级欧美特级ar全黄| 亚洲片在线资源| 国产精品视频播放| 欧美特黄级在线| 98精品国产高清在线xxxx天堂| 日韩少妇与小伙激情| 原创国产精品91| 国产精品1区2区在线观看| 亚洲精品短视频| 亚洲第一精品久久忘忧草社区| 国产精品中文字幕在线观看| 一本色道久久综合狠狠躁篇的优点| 成人写真视频福利网| 国产精品入口福利| 国产国语videosex另类| 中文字幕精品久久| 午夜免费在线观看精品视频| 色悠悠久久88| 国模吧一区二区| 国产做受高潮69| 精品久久久久久久久久久久久| 亚洲影院污污.| 欧美日本在线视频中文字字幕| 国产性猛交xxxx免费看久久| 久久99精品久久久久久琪琪| 亚洲国产成人精品女人久久久| 国产高清视频一区三区| 狠狠色狠狠色综合日日小说| 欧美成人免费全部观看天天性色| 亚洲国产精品99久久| 国产综合久久久久久| 搡老女人一区二区三区视频tv| 国产欧美最新羞羞视频在线观看| 亚洲激情成人网| 欧美在线免费视频| 欧美精品在线视频观看| 中文字幕欧美日韩在线| 亚洲精品永久免费精品| 青青久久av北条麻妃海外网| 热re99久久精品国产66热| 国产一区二区色|