常用模組 PHP 錯誤處理

湯清麗發表於2019-10-26

第1章 錯誤報告級別

PHP 程式的錯誤一般歸屬於下列三個領域:

語法錯誤:

語法錯誤最常見,並且也容易修復。如:程式碼中遺漏一個分號。這類錯誤會阻止指令碼的執行。

執行時錯誤:

這種錯誤一般不會阻止PHP指令碼的執行,但會阻止當前要做的事情。輸出一條錯誤,但php指令碼繼續執行。

邏輯錯誤:

這種錯誤最麻煩,既不阻止指令碼執行,也不輸出錯誤訊息。

圖解 Apache Web 伺服器與 PHP 引擎的關係。

案例:

//語法錯誤,忘記加分號
echo "123"   

//執行時錯誤
echo '123';
function laowang(){
    echo '456';
}

laoliu();

//邏輯錯誤,想要輸出隔壁老王,結果出現的是帽子,在系統角度看,這並不是錯誤。
if(1==1){
    echo "帽子";
}else{
    echo "隔壁老王";
}

在 PHP 系統中,到底有哪些錯誤報告級別?

在 php.ini 中可以找到錯誤級別的說明和設定。

//表示開啟所有錯誤提示但遮蔽NOTICE錯誤
error_reporting = E_ALL & ~E_NOTICE 

//直接關閉所有錯誤提示,開發階段一般是on,但上線以後一般會選擇off
display_errors = off/on    
級別常量 錯誤值 錯誤報告描述
E_ERROR 1 致命的執行時錯誤(阻止指令碼執行)
E_WARNING 2 執行時警告(非致命性錯誤)
E_PARSE 4 從語法中解析錯誤
E_NOTICE 8 執行時注意訊息(可能是或可能不是一個問題)
E_CORE_ERROR 16 PHP啟動時初始化過程中的致命錯誤
E_CORE_WARNING 32 PHP啟動時初始化過程中的警告(非致命性錯)
E_COMPILE_ERROR 64 編譯時致命性錯
E_COMPILE_WARNING 128 編譯時警告(非致命性錯)
E_USER_ERROR 256 使用者自定義的致命錯誤
E_USER_WARNING 512 使用者自定義的警告(非致命性錯誤)
E_USER_NOTICE 1024 使用者自定義的提醒(經常是bug)
E_STRICT 2048 編碼標準化警告(建議如何修改以向前相容)
E_ALL 6143 所有的錯誤、警告和注意資訊
//錯誤值一般都是系統定義好的常量
echo E_ERROR; //1

//1 2 4 8 ... 6143原理
//利用的二進位制,採用亮燈的原理,錯了就亮。
//000000000001 ---> 就是第一個錯誤

在實際的開發中,沒有人關注什麼錯誤級別錯誤值什麼的,報錯了,看一眼大概啥型別的,直接找BUG就行了。

在實際的開發中,我們其實需要做大量的錯誤處理,寫功能比較容易,無非就是增刪改查,就像汽車,讓一輛汽車開起來並不難,但如果要做各種安全防護,就要麻煩的多,考慮的因素也非常多,說明書厚的跟字典一樣。

第2章 調整錯誤報告級別

動態設定 PHP 錯誤資訊是否輸出,只在當前指令碼生效,並不會影響php.ini全域性的設定。

  • display_errors: 是否開啟PHP輸出錯誤報告的功能。

    值為:On(預設輸出錯誤報告)、 Off(遮蔽所有錯誤資訊)

    在PHP指令碼中可呼叫ini_set( )函式,動態設定php.ini配置檔案.

    如:ini_set("display_errors","On"); //顯示所有錯誤資訊

    
    //設定是否輸出錯誤資訊
    ini_set('display_errors',"off");//關閉
    ini_set('display_errors',"on");//開啟
    ini_set('display_errors',0);//關閉
    ini_set('display_errors',1);//開啟
    //呼叫函式進行試驗
    aa();

error_reporting: 設定不同的錯誤報告級別。

error_reporting = E_ALL & ~E_NOTICE

-- 可以丟擲任何非注意的錯誤,預設值。

error_reporting = E_ERROR | E_PARSE | E_CORE_ERROR

-- 只考慮致命的執行時錯誤、新解析錯誤和核心錯誤。

error_reporting = E_ALL & ~(E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE)

-- 報告除使用者導致的錯誤之外的所有錯誤。

在PHP指令碼可以透過error_reporting( )函式動態設定錯誤報告級別。如:error_reporting(E_ALL);

//動態設定錯誤等級
error_reporting(E_ALL);
//試驗,報所有錯誤
echo $a;

//開啟除了notice以外的所有錯誤
error_reporting(E_ALL & ~E_NOTICE);
echo $a;

案例:

ini_set('display_errors',1);//開啟
error_reporting(E_ALL);//開啟所有錯誤

$sum=0;//此處如果遮蔽掉,初次使用sum時,變數未定義會notice報錯
for($i=0;$i<=10;$i++){
    $sum+=$i;
}
echo $sum;

strlen();//字串長度函式,不給引數,報warning警告錯誤,不會影響程式執行
echo "aaaaaaaa";
aa();//致命錯誤,呼叫一個不存在的函式時程式會終止執行。

php.ini 中錯誤設定選項(瞭解即可,無需深究)。

配置指令 預設值 描述
display_startup_errors Off 是否顯示PHP引擎在初始化時遇到的錯誤
log_errors Off 確定日誌語句記錄位置
error_log Null 設定錯誤可以傳送到syslog中
log_errors_max_len 1024 每個日誌項的最大長度,以位元組為單位,設定0表示指定最大長度。
ignore_repeated_errors Off 是否忽略同一個檔案、同一行發生的重複錯誤訊息
ignore_repeated_source Off 忽略不同檔案中和同一檔案中不同行發生的重複錯誤。
track_errors Off 啟動該指令會使PHP在$php_errormsg中儲存最近發生的錯誤資訊。

第3章 PHP 日誌的記錄方式

1)採用檔案記錄 (推薦使用)。

2) 錯誤日誌記錄到作業系統日誌中。

思考:為什麼要做日誌記錄?

1.方便自己開發的時候查詢,框架一般都自帶日誌功能,只需要開啟就OK。

2.可以藉助執行日誌開發相應的後臺日誌功能,給管理員查詢,方便管理。

3.1 採用檔案記錄

先配置 php.ini 檔案

error_reporting = E_ALL     //將向PHP傳送每個錯誤
    display_errors=Off          //不顯示錯誤報告
  * log_errors=On               //決定日誌語句記錄的位置
    log_errors_max_len=1024     //每個日誌項的最大長度
  * error_log=G:/myerror.log    //指定錯誤寫進的檔案

試驗:

a();//注意觀察日誌檔案
conunt();//注意觀察日誌檔案

以上記錄的是系統報錯的日誌。

思考:我能不能做一個使用者操作的人為的日誌?

使用函式:在 PHP 檔案中使用 error_log() 來記錄日誌,就可以將資訊寫入到 myerror.log 檔案中。

error_log("使用者xxx想刪除ID為69的使用者名稱,已經記錄到日誌,請注意這個小子");

引數參考手冊。

rigger_error() 函式記錄日誌

上一節中,我們使用error_log()報一個自定義的錯誤資訊,讓系統記錄,只記錄資訊。

而使用 trigger_error() 比 error_log 更加靈活一些,可指定等級和檔案位置。

//可利用系統提供的錯誤等級給日誌記錄自己定義好的錯誤資訊,預設為notic級別
trigger_error("使用者xxx想刪除ID為69的使用者名稱,已經記錄到日誌,請注意這個小子",E_USER_ERROR);

3.2 錯誤日誌記錄到作業系統日誌中

先配置 php.ini 檔案

    error_reporting = E_ALL     //將向PHP傳送每個錯誤
  * display_errors=Off          //不顯示錯誤報告
  * log_errors=On               //決定日誌語句記錄的位置
    log_errors_max_len=1024     //每個日誌項的最大長度
  * error_log=syslog            //指定錯誤寫進的檔案

使用四個函式來記錄日誌:

//define_syslog_variables(); 為系統日誌初始化配置
//openlog();                開啟一個日誌連結
//syslog();                 傳送一條日誌記錄
//closelog();               關閉日誌連結

試驗:

aa();//不再顯示日誌,而是記錄到系統日誌中去了。

目前的開發已經淘汰這種方式,4個函式必須同時使用,課後可自行試驗,程式碼如下:

define_syslog_variables(); 
openlog("PHP5", LOG_PID , LOG_USER);
syslog(LOG_WARNING, "警告報告向syslog中傳送的演示,警告時間: ".date("Y/m/d H:i:s"));
closelog();

如何檢視 Window 系統日誌。

計算機右鍵 ---> 管理(G) ---> 系統工具 ---> 事件檢視器 ---> Windows 日誌 ---> 應用程式

第4章 自定義錯誤處理

自定義錯誤報告的處理方式,可以完全繞過標準的PHP錯誤處理函式,這樣就可以按自己定義的格式列印錯誤報告,或改變錯誤報告列印的位置。

說白了就是不使用系統的錯誤提示,改為自己的。

set_error_handler() -- 設定使用者自定義錯誤處理。

引數:mixed set_error_handler ( callable $error_handler [, int $error_types = E_ALL | E_STRICT ] )

回撥函式:回來調取函式。

所謂的回撥函式:

function demo(){
    return "我才不要呢";
}

function demo2(){
    return "我也不要";
}
function result($suan){
    return $suan();
}
//將函式名demo1 函式名demo2 作為字串引數傳遞給result函式,那麼可以自動呼叫上面的函式,我們就說demo1,demo2是result的回撥函式
echo result('demo2');

案例:

//回撥函式也需要引數接收,參考手冊
/*
errno
第一個引數 errno,包含了錯誤的級別,是一個 integer。

errstr
第二個引數 errstr,包含了錯誤的資訊,是一個 string。

errfile
第三個引數是可選的,errfile, 包含了發生錯誤的檔名,是一個 string。

errline
第四個引數是一個可選項, errline, 包含了錯誤發生的行號,是一個 integer。
*/
function callbackset($errno,$errstr,$errfile,$errline){
    echo "自定義錯誤處理:錯誤級別:{$errno},錯誤資訊是:{$errstr}.所在檔案:{$errfile}的第{$errline}行";
}

set_error_handler("callbackset");//此處設定為報錯的返回資訊交給callbackset自行處理

echo $aa;

特別注意:E_ERROR、E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、E_COMPILE_WARNING是不會有效果的,通常會用原始的方式顯示。

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

相關文章