PHP 錯誤調查

一.定義:PHP錯誤是由PHP沒法讀懂執行的代碼引發的錯誤。php

二:錯誤日誌 error log
1.在php.ini 裏設置 log_errors = on, log文件位置 error_log=/tmp/php_errors.log
2.代碼裏設置ini_set('log_errors' , 1) ,log文件位置 ini_set('error_log','/tmp/php_errors.log')
若是 error_log值爲空,PHP會把錯誤傳遞到web服務器,PHP錯誤會被記錄到web服務器的錯誤日誌裏。
在Apache 服務器,錯誤日誌文件路徑在httpd.conf : ErrorLog "/var/log/apache2/error_log"
若是你沒法找到Apache 錯誤日誌的位置,你能夠在你的錯誤代碼以前添加 
ini_set('log_errors' , 1)   
ini_set('error_log','/tmp/php_errors.log')
確保web服務器有寫入 error_log的權限,若是沒有的話,PHP會繼續使用web服務器的錯誤日誌文件。程序員

三:錯誤打印 error printing
除了寫入錯誤日誌,PHP還支持把錯誤輸出到頁面,或者是在命令行界面標準輸出。打開錯誤打印的設置:
1.在php.ini裏設置display_errors =1
2.ini_set('display_errors')web

若是你正確配置了全部的這些參數,可是錯誤信息沒有輸出,並且錯誤日誌裏也沒有任何信息,或者界面出現白屏,怎麼辦?apache

四:錯誤報告 error reporting
除了能夠配置錯誤日誌的位置,PHP容許你來配置系統中哪些錯誤被當作錯誤來處理。這一操做可經過:error_reporting或者 error_reporting ini 實現
舉例:小程序

error_reporting(E_ALL | E_STRICT);  //trust us on this line for now
echo $foo;
echo "Done","\n";

若是你運行以上代碼會出現: Notice : Undefined variable :foo in ......
若是是安全

error_reporting(E_PARSE);  //trust us on this line for now
echo $foo;
echo "Done","\n";

 PHP不會輸出或者記錄任何錯誤。
 服務器

五:錯誤級別 Error level
PHP目前有16個錯誤級別網絡

E_ERROR
E_WARNING
E_PARSE
E_NOTICE
E_CORE_ERROR
E_CORE_WARNING
E_COMPILE_ERROR
E_COMPILE_WARNING
E_USER_ERROR
E_USER_WARNING
E_USER_NOTICE
E_STRICT
E_RECOVERABLE_ERROR
E_DEPRECATED
E_USER_DEPRECATED
E_ALL

 

六:定製化錯誤處理
set_error_handle 容許用戶定義本身的錯誤處理方法。
 app

#File: example.php
function ourMagicErrorHandler($error_level, $error_string, $error_file, $error_line, $error_context)
{
    echo "An error happened but we're not going to say which one","\n";
    return true;
}
set_error_handler('ourMagicErrorHandler');

error_reporting(E_ALL | E_STRICT);  //trust us on this line for now
echo $foo;
echo "Done","\n";

 

七:定製化錯誤處理的缺點
根據手冊,如下錯誤類型沒法使用定製化的方法進行處理:
E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING
在調用set_error_handler()方法的地方會發起E_STRICT報錯。
由於定製化錯誤處理是處理運行時錯誤,以上錯誤同時存在會致使set_error_handler()方法沒法被定義。因此一個自定義的錯誤處理方法沒法在同一個文件裏同時處理這些錯誤。
許多初學者,甚至中級開發者,想要在定製化錯誤處理方法中記錄這些錯誤。雖然沒有什麼能夠阻止你這樣作,可是上面的警告明確告訴你這樣不會捕捉到你係統中全部的錯誤,同時監控全部的錯誤日誌也是很重要。框架

八:檢查錯誤處理程序
由於沒有get_error_handler方法,因此你沒法得知一個錯誤是否已經存在相應的錯誤處理程序。因此你須要一個比較尷尬的方式來獲取你須要的信息。
當你設置一個錯誤處理程序的時候:

$result = set_error_handler(array('Valid', 'callback'));

 

返回值就是你將要替換掉處理器的方法名。若是以前不存在這樣的一個處理程序,返回結果是NULL。幸運的是,restore_error_handle方法容許你重置最近一次的set_error_handler方法調用。

九:異常 Exception
PHP中未被捕捉的異常會建立一個E_ERROR錯誤,並且PHP會停止運行。警告:這一未被捕捉的異常沒法被定製的錯誤處理器處理。
事實上,能夠採用set_exception_handler來監聽未被捕捉到到異常:

function ourMagicExceptionHandler($e)
{
    echo 'Someone threw an exception (type: <code>' . 
    get_class($e) . '</code>) and no one caught it.';
    return true;
}    
set_exception_handler('ourMagicExceptionHandler');
throw new Exception("Foo");
echo "Done";

可是,雖然你使用這種方法捕捉到了異常,你的程序仍是會在定製化處理器執行結束以後中止運行。

十:Runtime VS. php.ini
許多控制錯誤的配置能夠在php.ini或者在error_reporting or ini_set裏面設置,可是你偶爾仍是會發現一些奇怪的行爲可是卻沒有PHP錯誤。由於PHP處理錯誤的方法隨時會改變,你永遠沒法確保你看到了全部的錯誤。
像以前提到的,許多處理這種狀況的方法是在代碼裏臨時添加以下代碼:

error_reporting(E_ALL | E_STRICT); 
ini_set('log_errors','1');
ini_set('error_log','/tmp/my-custom-php-error-log.log');
ini_set('display_errors', '1');

 然而這樣並非萬無一失。PHP容許管理員禁用一些方法。許多服務器管理商會出於安全的考慮禁用 error_reporting 和 init_set 方法。除了這些功能,還有一些公開或者私有的PHP安全擴展,會限制咱們能或者不能添加一些運行時設置。

若是你是一個php開發,這是一些你須要瞭解的細節。

十一:查找php.ini文件

有時當你在你不熟悉的系統查找php.ini文件的時候會很是的困難。這是由於PHP會加載多個ini文件。PHP的ini文件的位置是在編譯的時候就設置
好的。除了主要的設置文件php.ini 文件,php還會查找以ini結尾的其餘配置文件,並在php.ini文件以後加載。
幸運的是,PHP有一種機制能夠展現這些ini文件的列表。若是你在命令行裏運行PHP,只須要在後面添加--ini標記:

$ php --ini
Configuration File (php.ini) Path: /usr/local/php5/lib
Loaded Configuration File:         /usr/local/php5-20130127-205115/lib/php.ini
Scan for additional .ini files in: /usr/local/php5/php.d
Additional .ini files parsed:      /usr/local/php5/php.d/10-extension_dir.ini,
/usr/local/php5/php.d/50-extension-apc.ini,
/usr/local/php5/php.d/50-extension-curl.ini,
/usr/local/php5/php.d/50-extension-intl.ini,

你就能夠獲取全部加載的php.ini文件以及他們的位置。

若是你是在服務器上運行,phpinfo()會輸出類似的內容:

固然,這是比較簡單的狀況,PHP永遠沒有辦法如此簡單
在文章的前面咱們曾提到,有些配置能夠在php.ini裏面設置,也能夠在ini_set 方法裏面設置。也能夠在服務器的配置文件裏面作些設置。
假設你在使用Apache服務器,意味着在httpd.conf 和.htaccess使用以下語法:

php_value display_errors 1

除此以外,PHP5.3引入了.user.ini文件。這一系統容許你在服務器目錄下建立.user.ini文件,php會解析這些文件獲取ini的值。雖然以ini結尾,這個文件的格式和.htaccess的格式是一致的。

最後,雖說不是嚴格意義上的ini文件,PHP有一個ini配置文件名爲auto_prepend_file。這一配置,容許你在php.ini主文件解析以前添加並解析文件。我曾碰到過多用戶配置各自的auto_prepend_file來加載各自的運行時設置。若是這一設置路徑未包含全路徑,PHP會在include_path裏查找該文件。

十二:定製PHP錯誤信息
PHP有一個方法你能夠調用來觸發本身的報錯信息,這些信息默認是E_USER_NOTICE級別,你能夠經過改變第二個參數來改變錯誤級別。

trigger_error('This is a custom notice.',E_NOTICE);

 十三:其餘錯誤日誌
還有另外兩個錯誤記錄方法程序員須要瞭解的:error_log 和 syslog。
根據手冊,error_log方法「發送錯誤到指定的錯誤處理路徑」。這並不意味這PHP會報錯。若是你是在web中訪問,錯誤會被直接發送到error log.若是你是在命令行模式下調用 error_log 方法,也會發送錯誤信息到error log,除非error log 沒有設置。若是error log ini沒有設置,命令行PHP會發送信息到標準錯誤輸出。
error_log方法總會執行它的職責,不管log_errors ini是否有設置。所以,error_log常常被框架用來確保信息被傳送到error log。即便會忽略log_errors的設置,error_log方法會按照error_log ini的設置指定一個文件位置(若是error_log未設置,默認指向web服務器日誌)。
syslog方法與error_log 相似,會直接發送一條信息到日誌系統。然而,它並非發送信息php日誌或者網絡服務器日誌,而是直接發送到操做系統到系統日誌。若是想了解更多信息,請查看手冊頁面:

$ man syslog.conf

你一般會看私人框架中開發者同時是系統管理員到狀況下看到這種操做,這樣一般是爲了讓全部到日誌同時出如今一個地方,方便查閱。大部分
Modern PHP開發更傾向把本身框架的系統獨立於特定的系統像 *nix‘s syslogd。

十四:eval方法中的錯誤(Errors During eval
像許多「終端開發不須要編譯東西同樣」,PHP語言有一個eval方法。eval方法容許用戶建立一個字符串類型的PHP代碼塊,而後像一個小程序同樣能夠運行。有一些出於安全的考慮使eval在開發圈中成爲一種熱門話題。咱們在此不作討論。有些錯誤的w/r/t你須要記住。
PHP主程序中的eval塊裏面的代碼在出現錯誤的時候也會經過set_error_handler方法把錯誤發送到定製到錯誤處理器中。然而,當PHP爲eval塊裏面到錯誤建立錯誤信息的時候,錯誤信息裏面的行號是eval塊裏面的行號,而不是PHP主程序裏面的行號。好比:
 

<?php    
echo "Foo";
echo "Baz";
eval('echo $foo;');

will issue the following error message

PHP Notice:  Undefined variable: foo in /path/to/example.php(4) : eval()'d code on line 1

錯誤裏面的line1是指eval裏面代碼塊的第一行,而不是PHP代碼的第一行。若是你像知道eval錯誤是在PHP主程序中在第幾行,請查找修飾語(這裏是4)
另外,還記得定製化錯誤處理器不能夠處理同一文件中特定類型的錯誤嗎(像E_PARSE)?這一規則在eval中一樣適用。


十五:最近的錯誤(The last error) $php_errormsg
就像以前提到的,PHP能夠從不少中錯誤類型中恢復。處理完一個錯誤以後,PHP會把錯誤信息填充到當前做用域中一個叫 $php_errormsg到變量中,以確保$php_errormsg老是可以拿到最近到一條錯誤信息(除非你離開了當前做用域)。我看到許多定製錯誤處理器用到了這一變量,因此或許你想了解下這個變量。
提示:php.ini中track_errors參數爲true時這一變量纔會被使用。

十六:錯誤控制操做符(The Error Control Operator)

PHP有一個錯誤控制/抑制運算符。把這一運算符放在任何一段可能出錯到PHP代碼以前,PHP會吞掉全部到錯誤。好比運行如下代碼本應該拋出一個爲定義變量到異常(undefined variable foo Notice):

function main()
{
    echo $foo;
}
@ main();

可是由於以前加了@符號,沒有產生任何錯誤。不行的是,錯誤彷彿徹底被吞掉了,既不會被顯示,又不會被記錄。追蹤錯誤出現的惟一途徑是以前提到的$php_errormsg。因此,理論上來說,被抑制的報錯仍是有辦法經過$php_errormsg來獲取到的。可是考慮到$php_errormsg只做用於錯誤發生的做用域,因此沒有額外的編碼是沒法直接獲取錯誤所發生的具體位置。因此這種方法的做用仍是被限制的。
大多數專業的我所知道和尊重的PHP開發都會盡量避免使用@符號。可是由於有時候一個極小的錯誤能夠經過@符號輕易的避免,可是可能卻要花費一天的時間也沒法追蹤到。總之,不到萬不得已不要使用@符號。

十七:Backtrace
雖然不是嚴格意義上的錯誤處理機制,debug_backtracedebug_print_backtrace常常被用在定製錯誤處理器中輸出PHP調用堆棧。PHP堆棧會列出到達一個特定深度/節點的所又途徑/方法--都是些有用的調試信息。
可是因爲可能出現信息量過大的狀況,致使堆棧輸出吃掉因此內存,因此你可能須要一個設置來控制輸出節點的深度:

xdebug.var_display_max_depth = 3

文章來源:
https://alanstorm.com/php_error_reporting/

相關文章
相關標籤/搜索