我可以使用set_error_handler()来捕获大多数PHP错误,但它不适用于致命(E_ERROR)错误,例如调用不存在的函数。是否有其他方法来捕捉这些错误?
我试图调用mail()为所有错误和运行PHP 5.2.3。
我可以使用set_error_handler()来捕获大多数PHP错误,但它不适用于致命(E_ERROR)错误,例如调用不存在的函数。是否有其他方法来捕捉这些错误?
我试图调用mail()为所有错误和运行PHP 5.2.3。
当前回答
你不能在一个已注册的shutdown函数中抛出一个异常:
<?php
function shutdown() {
if (($error = error_get_last())) {
ob_clean();
throw new Exception("fatal error");
}
}
try {
$x = null;
$x->method()
} catch(Exception $e) {
# This won't work
}
?>
但是您可以捕获请求并将其重定向到另一个页面。
<?php
function shutdown() {
if (($error = error_get_last())) {
ob_clean();
# Report the event, send email, etc.
header("Location: http://localhost/error-capture");
# From /error-capture. You can use another
# redirect, to e.g. the home page
}
}
register_shutdown_function('shutdown');
$x = null;
$x->method()
?>
其他回答
不是真的。之所以叫致命错误,是因为它们是致命的。你无法从中恢复过来。
PHP没有提供常规的方法来捕捉和恢复致命错误。这是因为在发生致命错误后通常不应恢复处理。字符串匹配输出缓冲区(正如PHP.net上描述的技术的原始帖子所建议的那样)绝对是不明智的。这是不可靠的。
从错误处理程序方法中调用mail()函数也有问题。如果你有很多错误,你的邮件服务器就会有大量的工作,你就会发现自己有一个杂乱的收件箱。为了避免这种情况,可以考虑运行cron定期扫描错误日志并相应地发送通知。您可能还想研究一下系统监控软件,比如Nagios。
关于注册一个shutdown函数:
的确,您可以注册一个shutdown函数,这是一个很好的答案。
这里的重点是,我们通常不应该试图从致命错误中恢复,特别是不应该对输出缓冲区使用正则表达式。我是在回复被接受的答案,它链接到php.net上的一个建议,这个建议已经被更改或删除了。
该建议是在异常处理期间对输出缓冲区使用正则表达式,并且在出现致命错误的情况下(通过匹配您可能期望的任何配置错误文本检测到),尝试进行某种恢复或继续处理。这不是一个推荐的做法(我相信这就是为什么我也找不到最初的建议。不是我忽略了它,就是php社区否定了它)。
It might be worth noting that the more recent versions of PHP (around 5.1) seem to call the shutdown function earlier, before the output buffering callback is envoked. In version 5 and earlier, that order was the reverse (the output buffering callback was followed by the shutdown function). Also, since about 5.0.5 (which is much earlier than the questioner's version 5.2.3), objects are unloaded well before a registered shutdown function is called, so you won't be able to rely on your in-memory objects to do much of anything.
因此,注册一个关闭函数是可以的,但是应该由关闭函数执行的任务可能仅限于少数温和的关闭过程。
这里的关键是给那些偶然遇到这个问题并在最初接受的答案中看到建议的人的一些智慧之语。不要正则化你的输出缓冲区。
您不能捕获/处理致命错误,但可以记录/报告它们。 为了快速调试,我修改了这段简单代码的一个答案
function __fatalHandler()
{
$error = error_get_last();
// Check if it's a core/fatal error, otherwise it's a normal shutdown
if ($error !== NULL && in_array($error['type'],
array(E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING,
E_COMPILE_ERROR, E_COMPILE_WARNING,E_RECOVERABLE_ERROR))) {
echo "<pre>fatal error:\n";
print_r($error);
echo "</pre>";
die;
}
}
register_shutdown_function('__fatalHandler');
从PHP 7.4.13开始,我的经验是程序中所有可能的错误和异常都可以用两个回调函数来捕获:
set_error_handler("ErrorCB");
set_exception_handler("ExceptCB");
ErrorCB只是以任何想要的方式报告其参数,并调用Exit()。
ExceptCB在其异常参数上调用“get”方法,并执行一些逻辑来确定文件、行和函数的位置(如果您想要详细信息,请询问我),并以任何所需的方式报告信息并返回。
try/catch的唯一需要是当@或isset()不够用时,你需要抑制某些代码的错误。对“main函数”使用try/catch而不设置处理程序会失败,因为它不能捕获所有错误。
如果有人发现代码产生了这个方法无法捕捉到的错误,请告诉我,我会编辑这个答案。这种方法不能拦截的一个错误是靠近PHP程序末尾的单个{字符;这将生成一个Parse错误,这要求您通过包含错误处理的Include文件运行主PHP程序。
我没有发现register_shutdown_function()的任何需要。
注意,我所关心的是报告错误,然后退出程序;我不需要从错误中恢复——这确实是一个更难的问题。
在PHP 7或更高版本中,致命错误或可恢复的致命错误现在会抛出错误实例。像任何其他异常一样,Error对象可以使用try/catch块捕获。
例子:
<?php
$variable = 'not an object';
try {
$variable->method(); // Throws an Error object in PHP 7 or higger.
} catch (Error $e) {
// Handle error
echo $e->getMessage(); // Call to a member function method() on string
}
https://3v4l.org/67vbk
或者您可以使用Throwable接口来捕获所有异常。
例子:
<?php
try {
undefinedFunctionCall();
} catch (Throwable $e) {
// Handle error
echo $e->getMessage(); // Call to undefined function undefinedFunctionCall()
}
https://3v4l.org/Br0MG
欲了解更多信息:http://php.net/manual/en/language.errors.php7.php