2024 年 PHP Conference Japan

錯誤處理函式

另請參閱

另請參閱 syslog()

目錄

新增註記

使用者貢獻的註記 9 則註記

tracerdx at tracerdx dot com
19 年前
我不斷看到錯誤類型/錯誤編號的限定清單以陣列形式呈現;在使用者註記和手冊本身中都是如此。例如,在此手冊條目的範例中,當嘗試區分錯誤報告中變數追蹤的行為時

<?php //...

// 將儲存變數追蹤的錯誤集合
$user_errors = array(E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE);

//然後...

if (in_array($errno, $user_errors)) {
//...任何操作
}

//... ?>

我的印象是 PHP 錯誤碼值是位元旗標值。使用位元遮罩不是更好嗎?所以我提出一個稍微好一點的方法
<?php //...

$user_errors = E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE;

//...等等...

if ($errno & $user_errors) {
//...任何操作
}

//... ?>
或者,對於那些不喜歡在 if 陳述式中使用整數作為條件的人

<?php
if (($errno & $user_errors) > 0) {
//...任何操作
}
?>

我認為這比使用「另一個」array() 結構和 in_array() 更有效率。

如果我錯了,而且 E_* 常數不應該以這種方式使用(例如,不能保證這些常數是位元化的,這很奇怪,因為它們在 php.ini 檔案中就是這樣設定的),那麼請刪除我。我只是不明白為什麼要用陣列,明明位元比較就可以運作,而且考慮到位元方法應該更有效率。
ptah at se dot linux dot org
20 年前
僅限 PHP5(僅使用 php5.0 測試過)。

如果您因為某些原因偏好例外而不是錯誤,並且您的自訂錯誤處理程式 (set_error_handler) 將錯誤包裝成例外,那麼您必須小心您的腳本。

因為如果您不是只呼叫例外處理程式,而是拋出例外,並且有一個自訂例外處理程式 (set_exception_handler)。而且在該例外處理程式內觸發了錯誤,您將會收到一個奇怪的錯誤
「致命錯誤:在第 0 行的未知位置拋出無堆疊框架的例外」

這個錯誤訊息並不是特別有用,對吧? :)

下面的例子將會導致這個錯誤。
<?php
類別 PHPErrorException 延伸 Exception
{
私有
$context = null;
公開 函數
__construct
($code, $message, $file, $line, $context = null)
{
parent::__construct($message, $code);
$this->file = $file;
$this->line = $line;
$this->context = $context;
}
};

函數
error_handler($code, $message, $file, $line) {
拋出 新
PHPErrorException($code, $message, $file, $line);
}

函數
exception_handler(Exception $e)
{
$errors = 陣列(
E_USER_ERROR => "使用者錯誤",
E_USER_WARNING => "使用者警告",
E_USER_NOTICE => "使用者注意",
);

顯示
$errors[$e->getCode()].': '.$e->getMessage().' 於 '.$e->getFile().
' 第 '.$e->getLine()." 行\n";
顯示
$e->getTraceAsString();
}

set_error_handler('error_handler');
set_exception_handler('exception_handler');

// 拋出一個帶有 /未知/ 錯誤碼的例外。
拋出 新 Exception('foo', 0);
?>

然而,這問題很容易修復,因為它只是粗心程式碼造成的。
例如,直接從 error_handler 呼叫 exception_handler 而不是拋出例外。這不僅解決了這個問題,而且速度更快。 雖然這會導致印出一個「普通的」未處理例外,如果只想顯示「設計好的」錯誤訊息,這並不是最終的解決方案。

那麼,該怎麼做呢?確保 exception_handler 中的程式碼不會造成任何錯誤!在這個例子中,一個簡單的 isset() 就可以解決它。

此致,C-A B.
shawing at gmail dot com
19 年前
雖然 root 使用者會寫入 'error_log' 和 'access_log' 檔案,但 Apache 使用者必須擁有 'error_log = filename' 所參考的檔案,否則將不會寫入任何日誌項目。

; 來自 php.ini
; 將錯誤記錄到指定的檔案。
error_log = /usr/local/apache/logs/php.errors

[root@www logs]$ ls -l /usr/local/apache/logs/php.errors
-rw-r--r-- 1 nobody root 27K 1月 27 16:58 php.errors
Stephen
17 年前
如果您將 PHP 作為 Apache 模組使用,則預設行為可能是將 PHP 錯誤訊息寫入 Apache 的錯誤日誌。這是因為 error_log .ini 指令可能設定為「error_log」,這也是 Apache 錯誤日誌的名稱。我認為這是故意的。

但是,如果您願意,可以透過設定不同的 error_log 值來區分 Apache 錯誤和 PHP 錯誤。我將我的寫在 /var/log 資料夾中。
mortonda at dgrmm dot net
17 年前
請注意,這裡列出的範例程式碼每次呼叫時都會呼叫 date() 函式。如果您的程式碼庫很複雜,且經常呼叫自訂錯誤處理程式,則最終可能會花費相當多的時間。我在一些程式碼上執行了一個效能分析器,發現 50% 的時間都花費在此錯誤處理程式中的 date 函式上。
theotek AT nowhere DOT org
18 年前
在錯誤處理函式中使用 debug_backtrace() 是完全可行的。來看看吧

<?php
set_error_handler
('errorHandler');

function
errorHandler( $errno, $errstr, $errfile, $errline, $errcontext)
{
echo
'進入 '.__FUNCTION__.'() 位於第 '.__LINE__.' 行
"\n\n---錯誤碼---\n". print_r( $errno, true).
"\n\n---錯誤訊息---\n". print_r( $errstr, true).
"\n\n---錯誤檔案---\n". print_r( $errfile, true).
"\n\n---錯誤行數---\n". print_r( $errline, true).
"\n\n---錯誤上下文---\n".print_r( $errcontext, true).
"\n\nerrorHandler() 的回溯追蹤\n".
print_r( debug_backtrace(), true);
}

function
a( )
{
//echo "a() 的回溯追蹤\n".print_r( debug_backtrace(), true);
asdfasdf; // 錯誤
}

function
b()
{
//echo "b() 的回溯追蹤\n".print_r( debug_backtrace(), true);
a();
}

b();
?>

輸出

<raw>

進入 errorhandler() 位於第 9 行

---錯誤碼---
8

---錯誤訊息---
使用未定義的常數 asdfasdf - 假設為 'asdfasdf'

---錯誤檔案---
/home/theotek/test-1.php

---錯誤行數---
23

---錯誤上下文---
陣列
(
)

errorHandler() 的回溯追蹤
陣列
(
[0] => 陣列
(
[function] => errorhandler
[args] => 陣列
(
[0] => 8
[1] => 使用未定義的常數 asdfasdf - 假設為 'asdfasdf'
[2] => /home/theotek/test-1.php
[3] => 23
[4] => 陣列
(
)

)

)

[1] => 陣列
(
[file] => /home/theotek/test-1.php
[line] => 23
[function] => a
)

[2] => 陣列
(
[file] => /home/theotek/test-1.php
[line] => 30
[function] => a
[args] => 陣列
(
)

)

[3] => 陣列
(
[file] => /home/theotek/test-1.php
[line] => 33
[function] => b
[args] => 陣列
(
)

)

)

</raw>

因此,回溯追蹤陣列的第一個成員並不令人意外,除了缺少「檔案」和「行數」成員之外。

回溯追蹤的第二個成員似乎是 Zend 引擎內部用於觸發錯誤的鉤子。

其他成員則是正常的回溯追蹤。
jbq at caraldi dot com
17 年前
關於使用 syslog 設定 error_log 的精確說明:syslog() 呼叫是以 NOTICE 的嚴重性完成的。
匿名
19 年前
在 php.ini 中設定錯誤日誌檔時,您可以使用絕對路徑或相對路徑。相對路徑會根據產生腳本的位置來解析,您會在每個放置腳本的目錄中都得到一個日誌檔。如果您希望所有錯誤訊息都寫入同一個檔案,請使用檔案的絕對路徑。

在某些應用程式開發方法中,存在應用程式根目錄的概念,以「/」表示(即使在 Windows 上也是如此)。然而,PHP 似乎沒有這個概念,在 Windows 上,使用「/」作為日誌檔案路徑的起始字元會產生奇怪的行為。

如果您在 Windows 上運行,並且在 php.ini 中設定了

error_log = "/php_error.log"

您會收到一些(但不是全部)錯誤訊息。該檔案會出現在

c:\php_error.log

並包含內部產生的錯誤訊息,讓錯誤日誌記錄看起來像是正常運作。然而,由 error_log() 要求的日誌訊息並不會出現在這裡,或任何其他地方,看起來像是包含這些訊息的程式碼沒有被處理。

顯然在 Windows 上,內部產生的錯誤會將「/」解釋為「C:\」(或者如果您將 Windows 安裝在其他磁碟機上,則可能是不同的磁碟機 - 我沒有測試過)。然而,error_log 處理程序顯然找不到「/」——這也合情合理——於是訊息就被靜默地丟棄了。
petrov dot michael () gmail com
17 年前
我發現在強制 display_errors 設定為 off 的伺服器上,除錯語法錯誤非常不方便,因為它們會導致致命的啟動錯誤。我使用了以下方法來繞過這個限制

語法錯誤位於檔案 "syntax.php" 中,因此我建立了一個檔案 "syntax.debug.php",並包含以下程式碼

<?php
error_reporting
(E_ALL);
ini_set('display_errors','On');

include(
'syntax.php');
?>

這個 5 行的檔案保證沒有錯誤,允許 PHP 在包含先前導致致命啟動錯誤的檔案之前執行其中的指令。現在,這些致命的啟動錯誤變成了執行階段的致命錯誤。
To Top