PHP Conference Japan 2024

错误处理函数

另请参阅

另请参阅 syslog()

目录

添加注释

用户贡献的注释 9 条注释

5
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 文件中的设置方式就是这样),那么请删除我。我只是不明白为什么在按位比较可以工作的情况下应该使用数组,考虑到按位方法应该效率更高。
4
ptah at se dot linux dot org
20 年前
仅限 PHP5(仅在 php5.0 中测试过)。

如果您出于某种原因更喜欢异常而不是错误,并且您的自定义错误处理程序(set_error_handler)将错误包装到异常中,则必须小心使用您的脚本。

因为如果您不是只调用异常处理程序,而是抛出异常,并且有一个自定义异常处理程序(set_exception_handler)。如果在该异常处理程序内部触发了错误,您将收到一个奇怪的错误
"致命错误:在 Unknown 的第 0 行抛出异常,但没有堆栈帧"

此错误的信息量并不大,是吗? :)

下面的示例将导致此错误。
<?php
class PHPErrorException extends Exception
{
private
$context = null;
public function
__construct
($code, $message, $file, $line, $context = null)
{
parent::__construct($message, $code);
$this->file = $file;
$this->line = $line;
$this->context = $context;
}
};

function
error_handler($code, $message, $file, $line) {
throw new
PHPErrorException($code, $message, $file, $line);
}

function
exception_handler(Exception $e)
{
$errors = array(
E_USER_ERROR => "用户错误",
E_USER_WARNING => "用户警告",
E_USER_NOTICE => "用户通知",
);

echo
$errors[$e->getCode()].': '.$e->getMessage().' in '.$e->getFile().
' on line '.$e->getLine()."\n";
echo
$e->getTraceAsString();
}

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

// 使用/未知/错误代码抛出异常。
throw new Exception('foo', 0);
?>

但是,对此有一个简单的解决方法,因为它仅仅是由糟糕的代码导致的。
例如,直接从 error_handler 调用 exception_handler 而不是抛出异常。这不仅可以解决此问题,而且速度更快。尽管这会导致打印“常规”未处理异常,并且如果只希望“设计”错误消息,这不是最终的解决方案。

那么,该怎么办?确保 exception_handlers 中的代码不会导致任何错误!在这种情况下,一个简单的 isset() 就可以解决问题。

此致,C-A B。
3
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 Jan 27 16:58 php.errors
2
Stephen
17 年前
如果您将 PHP 作为 Apache 模块使用,则其默认行为可能是将 PHP 错误消息写入 Apache 的错误日志。这是因为 error_log .ini 指令可能设置为等于 "error_log",而 "error_log" 也是 Apache 错误日志的名称。我认为这是故意的。

但是,如果您希望将 Apache 错误与 PHP 错误分开,只需为 error_log 设置不同的值即可。我将我的错误日志写入 /var/log 文件夹中。
2
mortonda at dgrmm dot net
17 年前
请注意,此处列出的示例代码每次调用时都会调用 date()。如果您有一个复杂的源代码库,并且经常调用自定义错误处理程序,那么最终可能会花费相当长的时间。我使用分析器对一些代码进行了分析,发现 50% 的时间都花在了此错误处理程序中的 date 函数上。
2
theotek AT nowhere DOT org
18 年前
完全可以在错误处理函数中使用 debug_backtrace()。请看这里

<?php
set_error_handler
('errorHandler');

function
errorHandler( $errno, $errstr, $errfile, $errline, $errcontext)
{
echo
'Into '.__FUNCTION__.'() at line '.__LINE__.
"\n\n---ERRNO---\n". print_r( $errno, true).
"\n\n---ERRSTR---\n". print_r( $errstr, true).
"\n\n---ERRFILE---\n". print_r( $errfile, true).
"\n\n---ERRLINE---\n". print_r( $errline, true).
"\n\n---ERRCONTEXT---\n".print_r( $errcontext, true).
"\n\nBacktrace of errorHandler()\n".
print_r( debug_backtrace(), true);
}

function
a( )
{
//echo "a()'s backtrace\n".print_r( debug_backtrace(), true);
asdfasdf; // oops
}

function
b()
{
//echo "b()'s backtrace\n".print_r( debug_backtrace(), true);
a();
}

b();
?>

输出

<raw>

进入 errorhandler() 在第 9 行

---ERRNO---
8

---ERRSTR---
使用未定义的常量 asdfasdf - 假设为 'asdfasdf'

---ERRFILE---
/home/theotek/test-1.php

---ERRLINE---
23

---ERRCONTEXT---
数组
(
)

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>

因此,回溯数组的第一个成员并不令人意外,除了缺少 "file" 和 "line" 成员。

回溯的第二个成员似乎是 Zend 引擎内部的一个钩子,用于触发错误。

其他成员是正常的回溯。
1
jbq at caraldi dot com
17 年前
关于使用 syslog 配置 error_log 的详细信息:syslog() 调用使用严重性 NOTICE 执行。
1
Anonymous
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 进程显然找不到 "/" - 这是可以理解的 - 并且消息会静默地被丢弃。
-2
petrov dot michael () gmail com
17 年前
我发现,在强制 display_errors 关闭的服务器上,调试语法错误非常不方便,因为它们会导致致命的启动错误。我使用了以下方法来绕过此限制

语法错误位于文件 "syntax.php" 中,因此我创建了一个文件 "syntax.debug.php",其中包含以下代码

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

include(
'syntax.php');
?>

这个 5 行文件保证没有错误,允许 PHP 在包含之前导致致命启动错误的文件之前执行其中的指令。现在,这些致命的启动错误变成了运行时致命错误。
To Top