摘要:源碼分析錯誤及異常處理機制錯誤及異常處理機制文件是,在框架引導文件的的基礎文件中注冊不知道的可以去看源碼分析二入口篇,通過進行的注冊。異常中止處理將錯誤信息托管至寫入日志通過獲取最后拋出的錯誤,把信息托管至,在通過異常處理函數進行記錄信息。
源碼分析 錯誤及異常處理機制
錯誤及異常處理機制文件是/thinkphp/library/think/Error.php,在框架引導文件的的基礎文件base.php中注冊(不知道的可以去看《《源碼分析(二)—入口篇》》),通過thinkError::register()進行的注冊。
/** * 注冊異常處理 * @access public * @return void */ public static function register() { error_reporting(E_ALL); set_error_handler([__CLASS__, "appError"]); set_exception_handler([__CLASS__, "appException"]); register_shutdown_function([__CLASS__, "appShutdown"]); }
該方法做了四件事情:
設置報錯級別 E_ALL為E_STRICT所有報錯。
設置錯誤處理函數,set_error_handler([__CLASS__, "appError"])
設置異常處理函數,set_exception_handler([__CLASS__, "appException"]);
設置程序異常終止處理函數,register_shutdown_function([__CLASS__, "appShutdown"]);
PHP報錯級別php的報錯級別有:E_STRICT,E_ALL, E_USER_WARNING等,具體可查看[php
預定義常量]。
thinkphp中注冊了thinkError::appError()方法對錯誤進行處理。
/** * 錯誤處理 * @access public * @param integer $errno 錯誤編號 * @param integer $errstr 詳細錯誤信息 * @param string $errfile 出錯的文件 * @param integer $errline 出錯行號 * @return void * @throws ErrorException */ public static function appError($errno, $errstr, $errfile = "", $errline = 0) { $exception = new ErrorException($errno, $errstr, $errfile, $errline); // 符合異常處理的則將錯誤信息托管至 thinkexceptionErrorException if (error_reporting() & $errno) { throw $exception; } self::getExceptionHandler()->report($exception); }
在appError方法中,把符合異常處理的則將錯誤信息托管至系統的ErrorException,其他的異常通過thinkexceptionHandle進行處理。
//thinkexceptionErrorException文件 /** * ThinkPHP錯誤異常 * 主要用于封裝 set_error_handler 和 register_shutdown_function 得到的錯誤 * 除開從 thinkException 繼承的功能 * 其他和PHP系統ErrorException功能基本一樣 */ class ErrorException extends Exception { /** * 用于保存錯誤級別 * @var integer */ protected $severity; /** * 錯誤異常構造函數 * @param integer $severity 錯誤級別 * @param string $message 錯誤詳細信息 * @param string $file 出錯文件路徑 * @param integer $line 出錯行號 * @param array $context 錯誤上下文,會包含錯誤觸發處作用域內所有變量的數組 */ public function __construct($severity, $message, $file, $line, array $context = []) { $this->severity = $severity; $this->message = $message; $this->file = $file; $this->line = $line; $this->code = 0; empty($context) || $this->setData("Error Context", $context); } /** * 獲取錯誤級別 * @return integer 錯誤級別 */ final public function getSeverity() { return $this->severity; } }
errorException設置錯誤級別,錯誤信息,出錯文件路徑,行號,上下文。
對exception進行處理的是thinkexceptionHandle的report()方法:self::getExceptionHandler()->report($exception);
//self::getExceptionHandler() /** * 獲取異常處理的實例 * @access public * @return Handle */ public static function getExceptionHandler() { static $handle; if (!$handle) { // 異常處理 handle $class = Config::get("exception_handle"); if ($class && is_string($class) && class_exists($class) && is_subclass_of($class, " hinkexceptionHandle") ) { $handle = new $class; } else { $handle = new Handle; if ($class instanceof Closure) { $handle->setRender($class); } } } return $handle; }
這里有一個關鍵的地方是:static $handle; 聲明該變量是靜態變量時候,當賦值給該變量后,函數調用結束后不會銷毀,直到腳本結束才會銷毀。
這個邏輯就是判斷$handle是否已經賦值,沒有賦值,獲取默認配置文件是否設置處理handle,如果設置,這個handle必須是 hinkexceptionHandle的子類(is_subclass_of($class, " hinkexceptionHandle")),如果沒有設置,那么用默認的thinkexceptionHandle調用report方法進行處理, 記錄到日志文件中。
/** * Report or log an exception. * * @param Exception $exception * @return void */ public function report(Exception $exception) { if (!$this->isIgnoreReport($exception)) { // 收集異常數據 if (App::$debug) { $data = [ "file" => $exception->getFile(), "line" => $exception->getLine(), "message" => $this->getMessage($exception), "code" => $this->getCode($exception), ]; $log = "[{$data["code"]}]{$data["message"]}[{$data["file"]}:{$data["line"]}]"; } else { $data = [ "code" => $this->getCode($exception), "message" => $this->getMessage($exception), ]; $log = "[{$data["code"]}]{$data["message"]}"; } if (Config::get("record_trace")) { $log .= " " . $exception->getTraceAsString(); } Log::record($log, "error"); } }
把errorException的數據組裝成對應的字符串,寫入日志。
異常處理函數thinkphp中注冊了thinkError::appException()方法對錯誤進行處理。
/** * 異常處理 * @access public * @param Exception|Throwable $e 異常 * @return void */ public static function appException($e) { if (!$e instanceof Exception) { $e = new ThrowableError($e); } $handler = self::getExceptionHandler(); $handler->report($e); if (IS_CLI) { $handler->renderForConsole(new ConsoleOutput, $e); } else { $handler->render($e)->send(); } }
方法和appError處理差不多,基本都是通過獲取ExceptionHandle再調用handle的report方法,但是多了一步把異常呈現,如果是命令行寫到命令行輸出,如果是web的就把錯誤信息通過reponse響應返回客戶端。
異常中止時執行的函數thinkphp中注冊了thinkError::appShutdown()方法對錯誤進行處理。
/** * 異常中止處理 * @access public * @return void */ public static function appShutdown() { // 將錯誤信息托管至 thinkErrorException if (!is_null($error = error_get_last()) && self::isFatal($error["type"])) { self::appException(new ErrorException( $error["type"], $error["message"], $error["file"], $error["line"] )); } // 寫入日志 Log::save(); }
通過error_get_last()獲取最后拋出的錯誤,把信息托管至thinkErrorException,在通過異常處理函數進行記錄信息。最后寫入日志。
總結整體整個錯誤處理機制都是通過獲取ExceptionHandle再調用handle的report方法,但是多了一步把異常呈現,如果是命令行寫到命令行輸出,如果是web的就把錯誤信息通過reponse響應返回客戶端。默認的處理handle是thinkexceptionHandle,當然也可以自定義handle,但是必須是thinkexceptionHandle的子類, 通過self::getExceptionHandler的is_subclass_of($class, " hinkexceptionHandle")可以知。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/30147.html
摘要:源碼分析開門篇生命周期入口文件用戶發起的請求都會經過應用的入口文件,通常是文件。注冊錯誤和異常機制執行注冊錯誤和異常處理機制。由三部分組成應用關閉方法錯誤處理方法異常處理方法注冊應用關閉方法是為了便于攔截一些系統錯誤。 源碼分析—開門篇 thinkphp生命周期 1、入口文件 用戶發起的請求都會經過應用的入口文件,通常是 ==public/index.php==文件。當然,你也可以更改...
摘要:源碼分析入口篇源碼分析應用入口用戶發起的請求都會經過應用的入口文件,通常是文件。當然,你也可以更改或者增加新的入口文件。通常,我們不建議在應用入口文件中加入過多的代碼,尤其是和業務邏輯相關的代碼。 源碼分析---入口篇 源碼分析 應用入口 用戶發起的請求都會經過應用的入口文件,通常是 ==public/index.php==文件。當然,你也可以更改或者增加新的入口文件。 通常入口文件的...
摘要:關于拋出異常如在我的上一篇文中所說的一樣在接口的設計中接口的返回的數據是非常重要的例如無法避免的等等這些都是要命的錯誤同時還有一個極大的問題就是在新增模塊中例如我最近需要新增一個的分詞查詢模塊這個在添加索引刪除索引等等操作的時候是非常容易導 showImg(http://pqykjwm6s.bkt.clouddn.com/Grassland_Scenery_by_Shi_Yuejun....
摘要:會依據協議,將請求的數據等信息發送給解析器,接下來解析器會解析文件,初始化執行環境,然后處理請求,再以規定的格式返回處理后的結果,退出進程。它的特點是會在動態分配處理進程給請求,以達到提高效率的目的,大多數實現都會維護一個進程池。 PHP作為世界上最好的編程語音,被廣泛的運用到Web開發中。因為其語法和C類似,有著非常平緩的學習曲線,越來越多的人使用PHP進行Web產品的快速開發。PH...
摘要:源碼分析自動加載系統會調用方法注冊自動加載,在這一步完成后,所有符合規范的類庫包括依賴加載的第三方類庫都將自動加載。是通過加載對應的文件進行注冊加載的。 源碼分析 自動加載 系統會調用 Loader::register()方法注冊自動加載,在這一步完成后,所有符合規范的類庫(包括Composer依賴加載的第三方類庫)都將自動加載。 系統的自動加載由下面主要部分組成: 1. 注冊系統的自...
閱讀 3480·2021-11-19 09:40
閱讀 1496·2021-10-13 09:41
閱讀 2671·2021-09-29 09:35
閱讀 2715·2021-09-23 11:21
閱讀 1703·2021-09-09 11:56
閱讀 836·2019-08-30 15:53
閱讀 848·2019-08-30 15:52
閱讀 604·2019-08-30 12:47