检测(在自定义错误处理程序中)PHP 错误是否实际上被 @ 禁止


Detect (in custom error handler) if a PHP error was actually suppressed by @

上下文:

我有一个应用程序有三个环境:开发(本地(、测试/暂存(生产服务器(、生产。该应用程序知道哪个是哪个。暂存和生产上的错误报告均为 0,因此永远不会显示错误。在 dev 上,我想立即看到错误,我想在它们发生的地方看到它们,所以不是在某些日志中,而是在代码的结果中。

但是,我不想看到我用@明确禁止的错误。我一直在使用fsockopen,当它无法连接时会发出警告。我接受无连接,但不想看到错误。甚至在开发上也没有。

显然,所有错误都通过自定义错误处理程序,即使它们在代码中被禁止。

我的错误处理程序只有 4 个参数:errno、错误、文件、行。从那些我看不出错误最初是否被抑制。如果我能在那里看到,我可以选择是否打印错误(现在我总是这样做,如果 env=dev(。

有什么想法吗?或者也许关于如何完全忽略抑制的错误(这样它们甚至不会到达自定义错误处理程序(?

set_error_handler手册页中对此有提示。

[error_reporting() ] 值将为 0,如果导致错误的语句是 由 @ 错误控制运算符预置

当您使用错误控制运算符 @ 时,正在发生如下情况:

  1. 错误报告设置为 0(无错误(- error_reporting(0)
  2. 计算表达式
  3. 错误报告被设置回以前的值(即重新打开(

上面有点令人困惑的引用是指error_reporting返回当前设置的事实。如果使用控制运算符禁止显示错误,则调用error_reporting()将返回 0。

因此,如果您知道已将其设置为非零(即您报告了一些错误(并且它返回,则表明该错误已被抑制。

如果检测到抑制错误并想知道它是什么,则可以在变量$php_errormsg中找到它(如果track_errors设置为 php.ini 中的true(。

请注意,错误

控制运算符会导致大量开销,因为它每次使用时都会更改两次错误报告级别。它会减慢您的脚本速度。

对于 PHP 8.0

因此,在 PHP 8.0 中,您不再通过检查 error_reporting(( == 0 来判断错误/警告/通知等是否被抑制(使用 @(。

相反,它现在是一个相当长的带有常量的按位运算符,在此处的警告框中进行了描述:https://www.php.net/manual/en/language.operators.errorcontrol.php

修复了 PHP 7.x 和 8.x 的问题

在自定义错误处理程序中,如果要判断错误是否已使用 @ 符号禁止显示,请使用如下所示的内容:

$PHP_8_SUPPRESSED = E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR | E_PARSE;
$er = error_reporting();  
    
if ($er === 0 || $er === $PHP_8_SUPPRESSED) { 
  // do code because it was suppressed.  Ex: return FALSE, etc.
} 

在撰写本文时,$PHP_8_SUPPRESSED 将等于整数值 4437 ,但最好不要对其进行硬编码,因为未来的 PHP 版本可能会更改这些常量值。

快速旁注:我真的希望他们刚刚创建了一个名为"E_SUPPRESSED_ERROR"的新常量或我们可以检查的类似常量。但可悲的是他们没有!

在 php 中处理错误的正确方法

  • 请勿使用error_reporting
  • 安装一个错误到异常处理程序(http://www.php.net/manual/en/class.errorexception.php,示例 1(并将所有 PHP"错误"转换为异常
  • 在主代码中,在适当的情况下使用 try-catch
  • 安装异常处理程序以捕获主代码中未捕获的异常。此处理程序是输出和/或记录错误的唯一位置。
  • 不要使用@ .在极少数情况下,您希望忽略错误,请使用空的捕获块
  • 使用一些愚蠢的技巧来捕获"致命"错误。更好的是,联系php组并尝试说服他们在脚本中处理"致命"错误。