PHP 最佳實踐之異常和錯誤

蕭瀟發表於2017-07-26
異常

1).異常是Exception類的物件,在遇到無法修復的狀況時丟擲,例如遠端API沒有響應或者資料庫查詢失敗再或者是無法滿足程式執行的前置條件。出現問題的時候異常用於主動出擊,委託職責;異常還可以用於防守,預測潛在的問題來減輕影響。
2).Exception物件和其他的PHP物件一樣,使用new關鍵字例項化。

<?php
$exception = new Exception('userId cannot be null', 100);

第一個引數是訊息,第二個引數是數字程式碼。數字程式碼是可選的,用於為指定的異常提供上下文。我們可以使用公開的例項方法getCodegetMessage來獲得異常物件的兩個屬性。
3).假如遇到了異常情況,或者在當前的條件下無法操作,我們需要丟擲異常。

<?php
throw new Exception('Something went wrong.Time for lunch!');

4).我們必須丟擲Exception類或者他的子類,PHP內建的異常類和其子類如下:

  • Exception
  • ErrorException
    PHP標準庫提供了下述額外的Exception子類,擴充套件了PHP內建的異常類。
  • LogicException
    • BadFunctionCallException
    • BadMethodCallException
    • DomainException
    • InvalidArgumentException
    • LengthException
    • OutOfBoundsException
  • RuntimeException
    • OutOfBoundsException
    • OverflowException
    • RangeException
    • UnderflowException
    • UnexpectedValueException

5).捕獲異常。預測和捕獲並處理異常是我們自己的責任,因為未捕獲的異常可能會導致PHP應用終止執行,顯示錯誤資訊。攔截並處理潛在異常的方式是,把可能丟擲異常的程式碼放在在try/catch塊中。

try {
    $pdo = new PDO('mysql://host=wrong_host;dbname=wrong_name');
} catch (PDOException $e) {
    $code = $e->getCode();
    $message = $e->getMessage();
    echo 'Something went wrong.Check back soon, please';
    exit;
}

還可以連續丟擲多個異常

try {
  throw new Exception('Not a PDO exception');
  $pdo = new PDO('mysql://host=wrong_host;dbname=wrong_name');
} catch (PDOException $e) {
    echo 'Caught PDO exception';
} catch (Exception $e) {
    //處理其他異常
    echo 'Caught generic exception';
} finally {
    //這裡的程式碼始終都會執行
    echo 'Always do this';
}

捕獲某種異常的時候只會允許其中一個catch塊,如果PHP沒有找到適用的catch塊,異常會向上冒泡,直到PHP指令碼由於致命的錯誤而終止。
6).異常處理程式。我們可以使用一個全域性的異常處理程式,來捕獲所有未被捕獲的異常。異常捕獲程式都必須接受一個了型別為Exception的引數,異常捕獲程式使用set_exception_handler()函式註冊。

<?php
set_exception_handler(function (Exception $e) {
    //處理並記錄異常
});

//你的程式碼
...

//還原成之前的異常處理程式
restore_exception_handler();
錯誤

1).我們可以使用error_reporting()函式或者在php.ini檔案中使用errorreporting指令告訴PHP報告或者忽略那些錯誤。這兩種都是使用E*常量來確定。
2)錯誤報告方式四原則:

  • 一定要讓PHP報告錯誤
  • 在開發環境中要顯示錯誤
  • 再生產環境中不能顯示錯誤
  • 在開發和生產環境中都要記錄錯誤

3)一種php.ini配置的例子:
開發環境:

;顯示錯誤
display_startup_errors = On
display_errors = On
;報告所有錯誤
error_reporting = -1
; 記錄錯誤
log_errors = On

生產環境:

;不顯示錯誤
display_startup_errors = Off
display_errors = Off
;除了注意事項外,報告所有錯誤
error_reporting = E_ALL & ~E_NOTICE
; 記錄錯誤
log_errors = On

4).註冊全域性的錯誤處理程式:set_error_handler()函式。

<?php
set_error_handler(function($errno, $errstr, $errfile, $errline) {
    //處理錯誤
    //$errno表示錯誤等級對應E_*常量
    //$errcontext是一個省略的引數,高階除錯才用到
});

5.一個簡單的全域性錯誤處理程式的例子:

set_error_handler(function($errno, $errstr, $errfile, $errline) {
   if (!(error_reporting() & $errno)) {
    //error_reporting指令沒有設定這個錯誤,所以忽略
    return;  
  }
  throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
});

//其他程式碼

//還原成之前的錯誤處理程式
restore_error_handler();
相關處理元件
  • 開發環境: filp/whoops
  • 生產環境: monolog/monolog

專題系列

PHP專題系列目錄地址:https://github.com/xx19941215/webBlog
PHP專題系列預計寫二十篇左右,主要總結我們日常PHP開發中容易忽略的基礎知識和現代PHP開發中關於規範、部署、優化的一些實戰性建議,同時還有對Javascript語言特點的深入研究。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章