@ 错误抑制运算符和set_error_handler

@ error suppression operator and set_error_handler

提问人:Rok Kralj 提问时间:9/12/2011 最后编辑:CœurRok Kralj 更新时间:2/19/2023 访问量:3333

问:

我遵循良好的编程实践,并将PHP错误记录到文件中,而不是将其显示给用户。我用它来。set_error_handler()

现在问题来了。例如,我在某处:

@file_exists('/some/file/that/is/outside/openbasedir.txt');

但是,尽管有错误抑制运算符,错误消息仍会记录。我不想那样。我希望禁止的错误不要传递给我的错误处理程序。

PHP 日志记录 运算符-关键字 错误-报告

评论

3赞 KingCrunch 9/12/2011
避免使用 .这是一个好兆头,你做错了什么,不想修复它。但是,即使语句本身通过 “静音”,也会调用 errorhandler-callback。@@
2赞 tawfekov 9/12/2011
我完全同意 KingCrunch 的观点,隐藏错误真的是,你应该停止这样做BAD PRACTICE
1赞 Rok Kralj 9/12/2011
它们不是错误,而是通知。
2赞 KingCrunch 9/12/2011
你考虑用它来测试你的局部变量告诉我,你肯定做错了什么:初始化你的局部变量isset()
2赞 Rok Kralj 2/28/2012
Warning: file_exists(): open_basedir restriction in effect. File(/some/path) is not within the allowed path(s):,如果您知道如何在没有@操作员的情况下避免此警告,请协助。

答:

35赞 Arnaud Le Blanc 9/12/2011 #1

这个答案适用于 PHP 7:

运算符暂时将 error_reporting 设置为 0,因此您可以在错误处理程序中测试 error_reporting 的值:@

if (error_reporting() == 0)
    return;

或者更好的是,只记录error_reporting中的错误类型:

$error_reporting = error_reporting();
if ( !($error_reporting & $errno) )
    return;

此外,请查看 log_errorserror_log 选项,用于自动将错误记录到文件或系统日志中。

评论

0赞 Rok Kralj 9/12/2011
所以,基本上你是说@暂时将error_reporting设置为零?
11赞 Paul S 10/18/2016
对我不起作用(PHP7),但这确实有效:if (error_reporting() == 0) { return;
2赞 Chih-Hsuan Yen 6/23/2021
ini_get()在 PHP 8 上也不适合我。这样做:if ( !(error_reporting() & $errno) )
0赞 tereško 9/12/2011 #2

实际上,您应该避免使用运算符。首先,它很慢,我甚至可以说它是有害的。@

你应该在文件中有两行:php.ini

error_repoting = E_ALL | E_STRICT
display_errors = Off

...或者,如果您无权访问 php.ini 文件,则应在index.php(或任何其他引导文件)的顶部添加:

error_reporting( E_ALL | E_STRICT );
ini_set('display_errors', 0);

评论

1赞 laurent 12/29/2015
我没有投反对票,但只是说避免使用@并不能回答这个问题。PHP 有时会抛出可以捕获的异常,有时会显示无法捕获的愚蠢通知。在这种情况下,关闭整个应用程序的错误不是一个合理的解决方案。当场将它们静音也不理想,但稍微好一点(特别是对于像 file_exists 或 file_get_contents 这样的情况,它们在出错时已经返回 false,所以你不需要通知)。理想情况下,PHP在报告错误的方式上不会被破坏,但既然如此,我们就需要使用它。
1赞 Simon Backx 12/28/2018
您应该避免使用 @ 运算符,但有时您需要使用使用它们的库。
0赞 tereško 12/31/2018
@SimonBackx packagist 网站上不乏库。你也许可以找到一个更好的。现在已经不是 2011 年了:D
9赞 Simon Backx 12/28/2018 #3

也适用于 PHP 7 的解决方案

根据 PHP 文档:

如果您使用 set_error_handler() 设置了自定义错误处理函数,那么它仍将被调用,但此自定义错误处理程序可以(并且应该)调用 error_reporting(),当触发错误的调用前面有 @ 时,它将返回 0。

来源:http://php.net/manual/en/language.operators.errorcontrol.php

因此,您可以在错误处理程序中使用以下代码:

function exception_error_handler($errno, $errstr, $errfile, $errline ) {
    if (error_reporting() == 0) {
        /// @ sign temporary disabled error reporting
        return;
    }

    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}

set_error_handler("exception_error_handler");

评论

0赞 rosell.dk 8/19/2019
后续问题:由于 @ 符号暂时将错误报告设置为 0,因此似乎无法从错误处理程序中确定警告是由带有 @ 前面的代码触发的,或者是否在系统上禁用了错误报告。不过,我希望能够做到这一点,因为我有一种情况,尊重@但不尊重一般错误报告设置是有意义的。也许有一些解决方法吗?
0赞 Simon Backx 2/15/2020
您可以在代码的开头设置一个变量,并使用该变量来区分上述变量。另一个选项是用于检查 ini 文件,但这只有在您调整了配置文件中的错误报告时才有效。// @ sign temporary disabled error reportingini_get('error_reporting')
1赞 zxdx 5/17/2022 #4

手册

警告 在 PHP 8.0.0 之前,error_reporting() 在 自定义错误处理程序始终返回 0,如果错误被抑制 @ 运算符。从 PHP 8.0.0 开始,它返回值 E_ERROR | E_CORE_ERROR |E_COMPILE_ERROR |E_USER_ERROR |E_RECOVERABLE_ERROR | E_PARSE。

这意味着来自其他答案的解决方案将不起作用:(

恕我直言,@-operator 变得完全无法使用。

要禁用错误,您必须执行以下操作:

error_reporting(0); // disable

try {
    $res = 10/0;
} catch (Throwable){
    $res = false;
}

error_reporting(-1); // enable

评论

0赞 hakre 7/2/2022
好吧,PHP 8.0.0 给出的错误类会导致在 PHP 8.0.0 之前停止脚本的致命错误。因此,在操作员抑制消息而不是错误的情况下,抑制它们可能起作用。它也许更具体,你在这里给出的除以零的例子变成了一个错误(而且只是一个警告)IIRC。不确定那里完全无法使用的部分,也许仅除以零错误?
0赞 mbomb007 11/19/2022
这帮助我在升级到 PHP 8 后找到了错误的根源。谢谢。
0赞 Dima L. 11/22/2022
对于PHP8,请参阅我的答案: stackoverflow.com/a/74525266/610060
3赞 Dima L. 11/22/2022 #5

PHP8 行为已更改,签入错误处理程序不再起作用。在 PHP8 中检查使用 @ 抑制的错误的方法如下:error_reporting() == 0

function errorHandler($err_severity, $err_msg, $err_file, $err_line)
{
    // Skip errors suppressed by @
    if (!(error_reporting() & $err_severity)) {
        return true;
    }

    // Error handling here
    return false;
}
0赞 MartinM 2/19/2023 #6

PHP8 代码 4437 用于@

function myErrorHandler(int $errno, string  $errstr, ?string $errfile, ?int $errline) : void {
    if (error_reporting() !== 4437)
    {
      ......
    }
}

set_error_handler("myErrorHandler", E_ALL);

评论

1赞 Yunnosch 2/19/2023
欢迎来到 Stack Overflow!虽然这段代码可以解决这个问题,但包括解释它如何以及为什么解决这个问题,将真正有助于提高你的帖子的质量,并可能导致更多的赞成票。请记住,您是在为将来的读者回答问题,而不仅仅是现在提问的人。请编辑您的答案以添加解释,并指出适用的限制和假设。
0赞 Community 2/23/2023
您的答案可以通过其他支持信息进行改进。请编辑以添加更多详细信息,例如引文或文档,以便其他人可以确认您的答案是正确的。您可以在帮助中心找到有关如何写出好答案的更多信息。