php異常及錯誤信息捕獲並記錄日志實現方法全解析


php異常處理

什么是異常?

  • PHP 5 提供了一種新的面向對象的錯誤處理方法。異常處理用於在指定的錯誤(異常)情況發生時改變腳本的正常流程。這種情況稱為異常。
  • 當異常被觸發時,通常會發生:
    • 當前代碼狀態被保存
    • 代碼執行被切換到預定義的異常處理器函數
    • 根據情況,處理器也許會從保存的代碼狀態重新開始執行代碼,終止腳本執行,或從代碼中另外的位置繼續執行腳本
  • 當異常被拋出時,其后的代碼不會繼續執行,PHP 會嘗試查找匹配的 "catch" 代碼塊
  • 如果異常沒有被捕獲,而且又沒用使用 set_exception_handler() 作相應的處理的話,那么將發生一個嚴重的錯誤(致命錯誤),並且輸出 "Uncaught Exception" (未捕獲異常)的錯誤消息

php系統自帶異常處理:Exception

header("Content-type:text/html;charset=utf-8"); 
try 
{
    //業務處理 錯誤時拋出異常。 
    $age = 130; 
    if ($age > 120) { 
        throw new Exception('代碼學堂www.uxuew.cn。',888); 
    } 
}catch (Exception $e) { 
    $err = [ 
        'code' => $e->getCode(), 
        'msg'  => $e->getMessage(), 
        'file'    => $e->getFile(), 
        'line'   => $e->getLine() 
    ]; 
    echo json_encode($err); 
}
//輸出:{"code":888,"msg":"\u5e74\u9f84\u4e0d\u80fd\u5927\u4e8e120\u5c81\u3002","file":"\/ceshi.php","line":11} 

php自定義異常處理

header("Content-type:text/html;charset=utf-8"); 
class proException extends Exception 
{ 
    //根據業務需求,自定義方法 
    /** 
     * 獲取錯誤信息 
     * @param int $type 類型 1=json 2=數組 
     * @return array 
     */ 
    public function getErrorInfo($type = 2) 
    { 
        $err = [ 
            'code' => $this->getCode(), 
            'msg'  => $this->getMessage(), 
            'file'    => $this->getFile(), 
            'line'   => $this->getLine() 
        ]; 
        if ($type == 1) { 
            return json_encode($err); 
        } 
        return $err; 
    } 
} 
 
try 
{ 
    //業務處理 錯誤時拋出異常。 
    $site =$_SERVER['HTTP_HOST'] ; 
    if ($site == 'www.uxuew.cn') { 
        throw new proException('代碼學堂官網',999); 
    } 
} catch (proException $e) { 
    $info = $e->getErrorInfo(); 
    var_dump($info); 
} 
 
輸出:array(4){["code"]=>int(999) ["msg"]=>string(27)"代碼學堂官網" ["file"]=>string(17) "/ceshi.php" ["line"]=>int(53)} 

php還可以捕捉多個異常

header("Content-type:text/html;charset=utf-8"); 
class proException extends Exception 
{ 
    //根據業務需求,自定義錯誤方法 
    /** 
     * 獲取錯誤信息 
     * @param int $type 類型 1=json 2=數組 
     * @return array 
     */ 
    public function getErrorInfo($type = 2) 
    { 
        $err = [ 
            'code' => $this->getCode(), 
            'msg'  => $this->getMessage(), 
            'file'    => $this->getFile(), 
            'line'   => $this->getLine() 
        ]; 
        if ($type == 1) { 
            return json_encode($err); 
        } 
        return $err; 
    } 
} 
 
try 
{ 
    if ($_GET['age'] > 100) { 
        throw new proException('自定義的異常處理', 1002); 
    } else { 
        throw new Exception('系統的異常處理', 1002); 
    } 
} catch (proException $e) { 
    $info =  $e->getErrorInfo(); 
    var_dump($info);//自定義異常處理 
} catch (Exception $e) { 
    echo $e->getMessage();//系統異常處理 
} 

設置頂層異常處理器 (Top Level Exception Handler)

  • set_exception_handler() 函數可設置處理所有未捕獲異常的用戶定義函數
function myException($exception) 
{ 
echo "Exception: " , $exception->getMessage(); 
} 
 
set_exception_handler('myException'); 
throw new Exception('Uncaught Exception occurred'); 
  • 在上面的代碼中,不存在 "catch" 代碼塊,而是觸發頂層的異常處理程序。應該使用此函數來捕獲所有未被捕獲的異常

php錯誤處理

  • 在創建腳本和 web 應用程序時,錯誤處理是一個重要的部分。如果您的代碼缺少錯誤檢測編碼,那么程序看上去很不專業,也為安全風險敞開了大門
  • 如果在本地程序調試時出現系統致命性錯誤可以設置error_reporting(E_ALL)來顯示所有錯誤信息,但在服務器中我們是不能這樣做的,這樣很容易暴露系統信息,那么我們要如何處理系統錯誤呢
  1. 我們可以自定義系統報錯函數:
    • set_error_handler('errorHandler',E_ALL | E_STRICT) //設置錯誤處理器函數errorHandler,可以配合error_log函數實現日志記錄功能
    • 參數:
      • errorhandler 必需。規定用戶錯誤處理函數的名稱。
      • E_ALL|E_STRICT 可選。規定顯示何種錯誤報告級別的用戶定義錯誤。默認是 "E_ALL"。
    • 注:
      • E_ERROR、E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、E_COMPILE_WARNING是不會被這個句柄處理的,也就是會用最原始的方式顯示出來。不過出現這些錯誤都是編譯或PHP內核出錯,在通常情況下不會發生
      • 使用set_error_handler()后,error_reporting()將會失效。也就是所有的錯誤(除上述的錯誤)都會交給自定義的函數處理
  2. 捕獲系統致命性錯誤:
    • error_get_last() //獲取最后一次發生錯誤信息
    • register_shutdown_function('fatalErrorHandler') //在腳本停止執行時注冊一個回調函數
    • 注:通過以上兩個函數我們用可以監控系統致命性錯誤,比如服務器500錯誤,然后並記錄到日志文件中
    • 代碼實例:
//禁止錯誤輸出 
error_reporting(0); 
//設置錯誤處理器 
set_error_handler('errorHandler'); 
//在腳本結束時運行的函數 
register_shutdown_function('fatalErrorHandler'); 
 
/** 
* 錯誤處理 
* @param int    $err_no      錯誤代碼 
* @param string $err_msg  錯誤信息 
* @param string $err_file    錯誤文件 
* @param int    $err_line     錯誤行號 
* @return string 
*/ 
function errorHandler($err_no = 0, $err_msg = '', $err_file = '', $err_line = 0) 
{ 
    $log = [ 
        '['.date('Y-m-d h-i-s').']', 
        '|', 
        $err_no, 
        '|', 
        $err_msg, 
        '|', 
        $err_file, 
        '|', 
        $err_line 
    ]; 
    $log_path = '/data/mi/test.txt'; 
    error_log(implode(' ',$log)."\r\n",3, $log_path); 
    //echo implode(' ',$log).""; 
} 
 
/** 
* 捕捉致命錯誤 
* @return string 
*/ 
function fatalErrorHandler() { 
    $e = error_get_last(); 
    switch ($e['type']) { 
        case 1: 
            errorHandler($e['type'], $e['message'], $e['file'], $e['line']); 
            break; 
    } 
} 
 
class DemoClass_1 
{ 
    public function index() 
    { 
        //這里發生一個警告錯誤,出發errorHandler 
        echo $undefinedVarible; 
    } 
} 
 
$demo_1 = new DemoClass_1(); 
//這里發生一個警告錯誤,被errorHandler 捕獲 
$demo_1->index(); 
//發生致命錯誤,腳本停止運行觸發 fatalErrorHandler 
$demo_2 = new DemoClass_2(); 
$demo_2->index(); 
  • 打開echo后 輸出:
[2016-08-07 09-01-34] | 8 | Undefined variable: undefinedVarible | /data/mi/demo.php | 126

[2016-08-07 09-01-34] | 1 | Class 'DemoClass_2' not found | /data/mi/demo.php | 134
  • 備注:
    • register_shutdown_function 也可以用於API調試中,記錄每次請求值和返回值,方便調試
    • 利用 “|” 分割的好處是,便於利用 awk 對日志進行分割處理


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM