确定 error_reporting(0) 和 PHP 中的前置 @ 之间的区别

Determining the difference between error_reporting(0) and pre-pending @ in PHP

为 PHP 系统编写了自定义错误处理程序后,我想弄清楚如何确定错误报告级别(可以通过 error_reporting()) has been globally set to Off (0) or has been disabled for that line only using the @ prefix

获得)

目前的问题是,对于这两种情况,error_reporting() 函数 returns 0

更新 #1

不幸的是,此示例不适用于 CentOS 6.8 上的 PHP 5.3.3,因为 ini_get() 函数 returns 与 error_reporting()[ 的值相同=14=]

function errhandle($errno, $errstr, $errfile, $errline) {
    if (error_reporting() === 0 && error_reporting() === (int)ini_get('error_reporting')) {
        echo 'error_reporting(0) was used';
    } else if (error_reporting() === 0 && error_reporting() !== (int)ini_get('error_reporting')) {
        echo '@ was used';
    }
}

set_error_handler('errhandle');

echo error_reporting()."\n";
echo @$arr['name'];

// Prints
22527
error_reporting(0) was used

除了error_reporting(),您还可以通过ini_get('error_reporting')查看报错级别。从理论上讲,这很相似,但它有一个细微的差别,这使得它对您尝试做的事情很有价值。

如果已使用 error_reporting(0) 全局禁用错误报告,则 ini_get('error_reporting') 将 return 字符串 0。但是如果错误报告被单独留下并且该行以 @ 为前缀,它将 return 一个非零值(现有 INI 指令的值)。

因此您可以比较这 2 个值并准确确定发生了什么:

if (error_reporting() === 0 && error_reporting() === (int)ini_get('error_reporting')) {
    echo 'error_reporting(0) was used';
} else if (error_reporting() === 0 && error_reporting() !== (int)ini_get('error_reporting')) {
    echo '@ was used';
}

这只是您可以在自定义错误处理程序中执行的那种条件的示例。如果它不是您想要的,请告诉我,我会尝试调整它。

在我的 PHP 7.1.2 上本地测试(Windows 上的 CLI)。


更新#1

经过深思熟虑,我想出了这个主意。只是一个警告,这看起来非常 hacky 和低效,但我开始认为这可能是唯一的方法。

如果您正在按照 set_error_handler 文档中的 PHP 示例进行操作,那么您的自定义错误处理程序的函数签名可能如下所示:

function myErrorHandler($errno, $errstr, $errfile, $errline)

换句话说,您有发生错误的文件和行号。您可以使用此信息打开文件本身,查看行号,解析标记并查找 @ 字符。代码如下所示:

function myErrorHandler($errno, $errstr, $errfile, $errline) {
    $errfileContents = file($errfile);
    $errlineContents = $errfileContents[$errline - 1];
    $tokens = token_get_all('<?php ' . $errlineContents . ' ?>');
    if (error_reporting() === 0) {
        if (in_array('@', $tokens)){
            echo '@ was used';
        } else {
            echo 'error_reporting(0) was used';
        }
    }
}

显然,您可以通过检查是否使用了这两种技术来扩展该条件。

无论如何,它很丑陋,但它在我的 PHP 5.6.6(Windows 上的 CLI)上对我有用。