成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長資訊網
最全最豐富的資訊網站

聊聊在PHP7中對于Error的處理是怎樣的

前段時間在項目中遇到一個當時覺得比較奇怪的情況:使用 GuzzleHttp 發送 curl 請求,API 響應超時導致拋出異常。但 catch(Exception) 并沒有捕獲異常,導致代碼意外停止運行。后來查資料發現,在 PHP 7 中,GuzzleHttp 請求超時拋出的異常繼承的是 Error,而 Error 并沒有繼承 Exception,所以 catch(Exception) 無法捕獲并處理該異常。

PHP 7 中對 Error 的處理

在 PHP 5 中,當程序中有致命錯誤發生時,腳本會立即停止運行。并且,通過 set_error_handler 設置的錯誤處理程序在這種情況下并不會被調用。

【推薦學習:PHP7教程】

⒈ 自定義錯誤處理程序 set_error_handler

??set_error_handler 接受兩個參數,第一個為自定義的錯誤處理函數,第二個參數指定觸發該自定義錯誤處理函數的錯誤級別。但需要指出的是,在任何時候,只能有一個自定義的錯誤處理程序起作用。

function func_notice($num, $str, $file, $line) {     print "Encountered notice $num in $file, line $line: $strn"; } function func_error($num, $str, $file, $line) {     print "Encountered error $num in $file, line $line: $strn"; } set_error_handler("func_notice", E_NOTICE); set_error_handler("func_error", E_ERROR); echo $foo;

??以上代碼在執行以后,會輸出 PHP Notice: Undefined variable: foo 。在第二個 set_error_handler 執行以后,自定義錯誤處理函數變成了 func_error ,同時,觸發自定義錯誤處理函數的錯誤級別變成了 E_ERROR 。而在 PHP 中,變量未定義只會觸發 E_NOTICE 級別的錯誤,所以自定義的錯誤處理函數并不會被觸發。

需要指出的是,自定義的錯誤處理函數對以下幾種錯誤級別并不起作用:

E_ERROR、E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、E_COMPILE_WARNING、E_STRICT

??在上述幾種自定義錯誤處理程序無法處理的錯誤中,凡是以 ERROR 結尾的都是致命錯誤。其他幾種雖然不是致命錯誤,但

  • E_PARSE 是在解析 PHP 代碼時產生的錯誤,此時 PHP 代碼尚未開始運行,自定義錯誤處理程序自然無法處理該錯誤

  • E_CORE_WARNING 產生于 PHP 的初始化啟動階段,此時 PHP 代碼仍然尚未運行,所以不能被自定義錯誤處理程序處理

  • E_COMPILE_WARNING 是在 PHP 代碼的編譯階段產生,所以不能被自定義錯誤處理程序處理

而至于 E_STRICT 是 PHP 為了保證代碼的最佳互操作性和向前兼容而提出的代碼修改建議,自然也不會被自定義錯誤處理函數處理

function func_error($num, $str, $file, $line) {     print "Encountered error $num in $file, line $line: $strn"; } set_error_handler('func_error', E_NOTICE); $obj = 'foo'; $obj->method();

?? 以上代碼運行輸出結果:

PHP Fatal error:  Call to a member function method() on string

??雖然設置了自定義錯誤處理程序,但在致命錯誤發生時,并不起作用。

??對于這種自定義錯誤處理程序無法處理的致命錯誤,在 PHP 5 中可以通過注冊一個終止回調(shutdown_function)來記錄具體的錯誤信息,但也僅限于記錄錯誤信息,當發生致命錯誤時代碼仍然會停止運行。

$shutdownHandler = function(){     print PHP_EOL;     print "============================" . PHP_EOL;     print "Running the shutdown handler" . PHP_EOL;     $error = error_get_last();     if (!empty($error))     {         print "Looks like there was an error: " . print_r($error, true) . PHP_EOL;         // 可以添加記錄日志的邏輯     }     else     {         // 程序正常運行結束         print "Running a normal shutdown without error." . PHP_EOL;     } }; register_shutdown_function($shutdownHandler); $obj = 'foo'; $obj->method();

??以上代碼執行會輸出

PHP Fatal error:  Call to a member function method() on string in /home/chenyan/test.php on line 24 ============================ Running the shutdown handler Looks like there was an error: Array (     [type] => 1     [message] => Call to a member function method() on string     [file] => /home/chenyan/test.php     [line] => 24 )

⒉ 撤銷自定義錯誤處理程序

??當同時設置多個自定義錯誤處理程序時,雖然只有最后設置的自定義錯誤處理程序起作用。但所有設置的自定義錯誤處理程序會以棧的方式保存(FILO)。

??使用 restore_error_handler 可以撤銷最近一次設置的自定義錯誤處理程序;如果同時調用了多次 set_error_handler ,則每調用一次 restore_error_handler,處于棧頂的錯誤處理程序就會被撤銷。

function func_notice($num, $str, $file, $line) {     print "Encountered notice : $strn"; } set_error_handler("func_notice", E_NOTICE); set_error_handler("func_notice", E_NOTICE); set_error_handler("func_notice", E_NOTICE); echo $foo; set_error_handler("func_notice", E_NOTICE); echo $foo; restore_error_handler(); echo $foo; restore_error_handler(); echo $foo; restore_error_handler(); echo $foo; restore_error_handler(); echo $foo;

??以上代碼運行,會輸出:

Encountered notice : Undefined variable: foo Encountered notice : Undefined variable: foo Encountered notice : Undefined variable: foo Encountered notice : Undefined variable: foo Encountered notice : Undefined variable: foo PHP Notice:  Undefined variable: foo

⒊ PHP 7 中對錯誤的處理

??在 PHP 7 中,當有致命錯誤或 E_RECOVERABLE_ERROR 類型的錯誤發生時,通常會拋出一個 Error,程序并不會終止。

try {     $obj = 'foo';     $obj->method(); } catch (Error $e) {     echo $e->getMessage(); }

??運行以上代碼會輸出

Call to a member function method() on string

E_RECOVERABLE_ERROR 是一種可捕獲的致命錯誤,這種錯誤的出現并不會使得 Zend 引擎處于不穩定的狀態,但必須被捕獲并且處理。如果不處理,那么這種錯誤最終會變成 E_ERROR 類型的錯誤,最終導致 PHP 代碼停止運行。

??php 7 中,并不是所有的致命錯誤都會拋出 Error,一些特定情況下出現的致命錯誤( Out Of Memory)仍然會導致代碼停止運行。另外,如果拋出的 Error 沒有被捕獲并處理,則代碼仍然會停止運行。

// bak.sql 的大小為 377 M // PHP 配置的 memory_limit = 128M try {     $file = './bak.sql';     file_get_contents($file); } catch (Error $e) {     echo $e->getMessage(); } // 執行以上代碼,仍然會產生致命錯誤 PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 395191240 bytes) // 拋出的 Error 沒有被捕獲并處理,代碼依然會停止運行 $obj = 'foo'; $obj->method(); // 執行以上代碼,由于并沒有用 try/catch 捕獲并處理拋出的 Error,程序仍然會停止運行 PHP Fatal error:  Uncaught Error: Call to a member function method() on string

??PHP 7 中的 Error 并沒有繼承 Exception,之所以這樣做是為了防止 PHP 5 中捕獲并處理 Exception 的代碼捕獲這些 Error。因為在 PHP 5 中,這些致命錯誤是會導致代碼停止運行的。

??Error 和 Exception 都繼承自 Throwable 。在 PHP 7 中,Throwable 是一個 interface,所有能通過 throw 關鍵字拋出的對象都實現了這個 interface。

interface Throwable {     public function getMessage(): string;     public function getCode(): int;     public function getFile(): string;     public function getLine(): int;     public function getTrace(): array;     public function getTraceAsString(): string;     public function getPrevious(): Throwable;     public function __toString(): string; }

??需要指出的是,Throwable 是 PHP 底層的 interface,PHP 代碼中不能直接實現 Throwable 。之所以作出這個限制,是因為通常只有 Error 和 Exception 可以被拋出,并且這些拋出的 Error 和 Exception 中還存儲了它們被拋出的堆棧跟蹤信息,而 PHP 代碼中開發者自定義的 class 無法實現這些。

??要在 PHP 代碼中實現 Throwable 必須通過繼承 Exception 來實現。

interface CustomThrowable extends Throwable {} class CustomException extends Exception implements CustomThrowable {} throw new CustomException();

??PHP 7 中 Error 和 Exception 的繼承關系

interface Throwable     |- Exception implements Throwable         |- Other Exception classes     |- Error implements Throwable         |- TypeError extends Error         |- ParseError extends Error         |- AssertionError extends Error         |- ArithmeticError extends Error             |- DivizionByZeroError extends ArithmeticError
  • TypeError

??當函數的傳參或返回值的數據類型與申明的數據類型不一致時,會拋出 TypeError

function add(int $left, int $right) {     return $left + $right; } try {     $value = add('left', 'right'); } catch (TypeError $e) {     echo $e->getMessage(); } // 運行以上代碼,會輸出: Argument 1 passed to add() must be of the type int, string given

??當開啟嚴格模式時,如果 PHP 內建函數的傳參個數與要求的參數不一致,也會拋出 TypeError

declare(strict_types = 1); try {     substr('abc'); } catch (TypeError $e) {     echo $e->getMessage(); } // 運行以上代碼,會輸出: substr() expects at least 2 parameters, 1 given

??默認情況下,PHP 7 處于弱模式。在弱模式下,PHP 7 會盡可能的將傳參的數據類型轉換為期望的數據類型。例如,如果函數期望的參數類型為 string,而實際傳參的數據類型的 int,那么 PHP 會把 int 轉換為 string。

// declare(strict_types = 1); function add(string $left, string $right) {     return $left + $right; } try {     $value = add(11, 22);     echo $value; } catch (TypeError $e) {     echo $e->getMessage(); } // 以上代碼運行,會正常輸出 33,PHP 會對傳參的數據類型做轉換(int→string→int) // 但如將 PHP 改為嚴格模式,則運行是會拋出 TypeError Argument 1 passed to add() must be of the type string, int given
  • ParseError

??當在 include 或 require 包含的文件中存在語法錯誤,或 eval() 函數中的代碼中存在語法錯誤時,會拋出 ParseError

// a.php $a = 1 $b = 2 // test.php try {     require 'a.php'; } catch (ParseError $e) {     echo $e->getMessage(); } // 以上代碼運行會輸出: syntax error, unexpected '$b' (T_VARIABLE) // eval 函數中的代碼存在語法錯誤 try {     eval("$a = 1"); } catch (ParseError $e) {     echo $e->getMessage(); } // 以上代碼運行會輸出: syntax error, unexpected end of file
  • AssertionError

??當斷言失敗時,會拋出 AssertionError(此時要求 PHP 配置中 zend.assertions = 1,assert.exception = 1,這兩個配置可以在 php.ini 文件中配置,也可以通過 ini_set() 在 PHP 代碼中配置)。

ini_set('zend_assertions', 1); ini_set('assert.exception', 1); try {     $test = 1;     assert($test === 0); } catch (AssertionError $e) {     echo $e->getMessage(); } // 運行以上代碼會輸出: assert($test === 0)
  • ArithmeticError

??在 PHP 7 中,目前有兩種情況會拋出 ArithmeticError:按位移動操作,第二個參數為負數;使用 intdiv() 函數計算 PHP_INT_MIN 和 -1 的商(如果使用 / 計算 PHP_INT_MIN 和 -1 的商,結果會自動轉換為 float 類型)。

try {     $value = 1 << -1; } catch (ArithmeticError $e) {     echo $e->getMessage(); } // 運行以上代碼,會輸出: Bit shift by negative number try {     $value = intdiv(PHP_INT_MIN, -1); } catch (ArithmeticError $e) {     echo $e->getMessage(); } // 運行以上代碼,會輸出: Division of PHP_INT_MIN by -1 is not an integer
  • DivisionByZeroError

??拋出 DivisionByZeorError 的情況目前也有兩種:在進行取模(%)運算時,第二個操作數為 0;使用 intdiv() 計算兩個數的商時,除數為 0。如果使用 / 計算兩個數的商時除數為 0,PHP 只會產生一個 Warning。并且,如果被除數非 0,則結果為 INF,如果被除數也是 0,則結果為 NaN。

try {     $value = 1 % 0;     echo $value; } catch (DivisionByZeroError $e) {     echo $e->getMessage(), "n"; } // 運行以上代碼,會輸出: Modulo by zero try {     $value = intdiv(0, 0);     echo $value; } catch (DivisionByZeroError $e) {     echo $e->getMessage(), "n"; } // 運行以上代碼,會輸出: Division by zero

??通常在實際的業務中,捕獲并處理拋出的 Error 并不常見,因為一旦拋出 Error 說明代碼存在嚴重的 BUG,需要修復。所以,在實際的業務中,Error

贊(0)
分享到: 更多 (0)
?
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
我的妺妺H伦浴室无码视频| 无码成人精品区在线观看| 日韩精品久久久肉伦网站| 日本少妇被黑人猛CAO| 上面一个摸下面一个手念什么 | 乱色熟女综合一区二区三区| 免费精品一区二区三区第35| 人妻被修空调在夫面侵犯| 色综合色欲色综合色综合色综合R| 我趁老师睡觉偷偷的脱她内裤| 亚洲AV无码一区二区三区天堂| 亚洲中文字幕精品无码AV| 2021国产精品国产精华| 爸的比老公大两倍儿媳妇叫什么呢| 丰满少妇BBWBBW| 国产性夜夜春夜夜爽| 久久亚洲精品无码AV红樱桃| 人妻熟女一区二区AⅤ| 玩两个丰满老熟女| 亚洲日韩一页精品发布| BBBBBB嫩BBBBBB| 国产传媒精品1区2区3区| 精品性高朝久久久久久久| 农民工猛吸女大学奶头| 撕掉她的衣服吮的双乳游戏| 亚洲乱码日产精品BD在| CHINESE熟女老女人HD| 国产精品爆乳奶水无码视频| 久久久久亚洲精品无码网址蜜桃| 全力以赴的行动派第二季| 挺进绝色校花的紧窄小肉| 亚洲日韩国产一区二区三区在线| AV狠狠色超碰丁香婷婷综合久久| 国产精品SP调教打屁股| 久久久久久久女国产乱让韩| 人妻在卧室被老板疯狂进入| 亚洲AV无码一级毛片少妇| 607080岁奶奶| 国产成人无码AV一区二区| 久久久久亚洲精品无码网址色欲| 人人妻人人澡人人爽人人精品浪潮| 亚洲AV成人一区二区电影在线| 重生之玩遍娱乐圈全文阅读| 国产成人亚洲精品无码AV大片| 久久夜色精品国产| 双腿被绑成M型调教PⅠAY照片| 亚洲综合精品成人| 粉嫩Av网站在线观看| 久久精品国产亚洲AV麻豆网站 | 成在人线AV无码免费看| 久久99精品久久久久久清纯| 日韩精品成人无码专区免费| 亚洲中文字幕无码AV正片| 丁香花在线视频完整版| 久久人搡人人玩人妻精品首页 | 欧美VA国人精品VA| 亚洲AV无码一区二区三区久久精| AA级女人大片喷水视频免费| 国内精品免费久久久久电影院97| 欧洲精品不卡1卡2卡三卡 | 人人妻人人澡人人爽人人精品| 亚洲欧美在线一区中文字幕| 嗯~啊哈好深好骚啊哼| 麻豆国产在线精品国偷产拍| 无码一区在线视频| JAPANESE成熟丰满熟妇| 精品久久久无码人妻中文字幕豆芽| 日韩AV无码中文一区二区三区 | 成人免费无遮挡无码黄漫视频| 久久久国产精品一区二区18禁| 天天摸天天做天天爽天天弄| 777爽死你免费看一二区无码| 韩国办公室三级HD激情在线观看| 日产乱码一二三区别免费一| 在线播放五十路熟妇| 国产自无码视频在线观看| 日韩欧美午夜成人精品视频| 在线观看免费AV网站| 国产色视频一区二区三区QQ号| 热99RE久久免费视精品频| 野花香HD免费高清版6高清版 | 亚洲国产成人极品综合| 国产成人精欧美精品视频| 欧美疯狂性受XXXXX另类| 亚洲熟妇AV一区二区三区| 国产精品亚洲精品日韩已方| 人妻丝袜AV先锋影音先| 中文字幕V亚洲ⅤV天堂| 黑色丝袜老师自慰喷水浪潮免费 | 一本久道综合在线无码88| 国产亚洲欧洲网友拍| 日日摸日日踫夜夜爽无码| 98久9在线 | 免费| 久久天天躁狠狠躁夜夜不卡| 亚洲大尺度专区无码| 国产精品成人VA在线观看| 日本乱码卡一卡新区入口| 2020无码专区人妻系列日韩| 久久久久久亚洲精品成人| 亚洲成av人片在线观看| 国产裸体裸美女无遮挡网站| 色偷一区国产精品| VODAFONEWIFI暴力| 欧美 亚洲 日本 成人| 在公车被灌满JING液| 久久久精品人妻一区亚美研究所| 亚洲VA在线VA天堂VA无码| 国产精品无码不卡一区二区三区| 色欲香天天天综合网站无码| 波多野结衣在线观看av| 亲胸揉屁股膜下刺激视频免费网站| 14萝自慰专用网站| 麻豆精产国品一二三产区区| 亚洲午夜无码久久久久软件| 精品深夜AV无码一区二区| 亚洲成人免费av| 国内精品久久久久久久久电影网| 午夜.DJ高清免费观看视频| 国产精品多人P群无码| 婷婷四房综合激情五月在线| 国产SM调教视频在线观看| 少妇午夜福利水多多| 成人Α片免费视频在线观看| 人人做人碰人人添| 波多野结衣一二三区AV高清 | 久久婷婷人人澡人人喊人人爽| 亚洲熟妇色XXXXX中国少妇Y| 精品一卡二卡≡卡四卡日产乱码| 亚洲韩国精品无码一区二区三区| 激情视频传媒一区二区| 亚洲国产丝袜精品一区| 精品久久久久久久免费人妻| 亚洲乱码一区二区三区| 久久国产精品免费一区| 亚洲中文字幕久在线| 久久无码专区国产精品S| 一本无线乱码不卡一二三四 | 色又黄又爽18禁免费网站现观看| 成人欧美一区二区三区白人| 日韩人妻无码一区二区三区久久| 东京热人妻丝袜AV无码| 天天AV天天爽无码中文| 国产卡一卡二无线乱码| 亚洲AV熟妇高潮18P| 精品少妇人妻AV无码久久| 玉米地诱子偷伦初尝云雨孽欲| 蜜芽AⅤ色欲AV浪潮夜夜嗨| CAOPORN免费视频在线| 人人澡人人澡人人澡| 国产成人剧情AV麻豆映画| 小浪货腿打开水真多真紧| 精品9E精品视频在线观看| 又粗又硬又黄A级毛片| 欧美群交性爱视频| 纯爱无遮挡H肉动漫| 无码精品H动漫成人影院| 和教练在车里干了我三次| 亚洲日韩乱码中文无码蜜桃臀网站 | 一本一道人人妻人人妻| 嫩草在线视频WWW免费看| 成人动漫在线观看| 午夜福利1000集无码| 久久国产精品-国产精品| 2019四虎影视最新在线| 日日噜噜噜夜夜爽爽狠狠| 国产沙发午睡系列999| 亚洲综合欧美在线一区在线播放| 男男GAY无套国产| 俄罗斯另类ZOZO| 亚洲AV综合色区无码二区偷拍| 看久久久久久A级毛片| 宝宝握住坐下~它会自己动| 无码人妻AⅤ一区二区三区水密桃| 狠狠噜狠狠狠狠丁香五月| 中国CHINAGARY武警网站| 日本高清视频www| 国产日产欧产精品精品软件| 夜夜高潮夜夜爽高清视频一| 人妻少妇AV无码一区二区| 国产喷水1区2区3区咪咪爱AV| 一本一道久久A久久精品综合| 日本亲近相奷中文字幕视频| 国产做国产爱免费视频| 中文字幕欧美人妻精品一区| 少妇精品久久久久www| 久久99精品国产麻豆不卡| SEERX性欧美| 亚洲 精品 综合 精品 自拍| 旅人蕉天堂鸟的区别视频| 肥胖孕妇BBWBBWBBW| 亚洲人成无码网WWW电影麻豆| 全免费A级毛片免费看| 国精产品一二三四线免费| 69无人区码一码二码三码区别| 特黄 做受又硬又粗又大视频| 久久国产高潮流白浆免费观看 | 国产在线观看无码免费视频| 99久久精品无码专区| 亚洲av成人一区| 欧美最猛黑人XXXXX猛交|