@错误抑制运算符和set_error_handler

Posted

技术标签:

【中文标题】@错误抑制运算符和set_error_handler【英文标题】:@ error suppression operator and set_error_handler 【发布时间】:2011-11-14 21:33:16 【问题描述】:

我遵循良好的编程实践,我将 php 错误记录到文件中,而不是向用户显示。我为此使用set_error_handler()

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

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

但是尽管有错误抑制操作符,错误信息还是会记录下来。我不想要那个。我希望抑制的错误不会传递给我的错误处理程序。

【问题讨论】:

避免使用@。这是一个好兆头,表明您做错了什么并且不想修复它。但是,即使语句本身通过@“静音”,也会调用错误处理程序回调。 我完全同意 KingCrunch ,隐藏错误真的是BAD PRACTICE 你应该停止这样做 它们不是错误,它们是通知。 你考虑用isset() 测试你的局部变量告诉我,你肯定做错了什么:初始化你的局部变量! Warning: file_exists(): open_basedir restriction in effect. File(/some/path) is not within the allowed path(s):,如果您知道如何在没有@运算符的情况下避免此警告,请协助。 【参考方案1】:

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

if (ini_get('error_reporting') == 0) 
    return;

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

$error_reporting = ini_get('error_reporting');

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


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

【讨论】:

那么,基本上你是说@暂时将error_reporting设置为零? 对我不起作用(PHP7),但这确实有效: if (error_reporting() == 0) return; ini_get() 在 PHP 8 上也不适用于我。这样做了:if ( !(error_reporting() & $errno) )【参考方案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);

【讨论】:

我没有投反对票,只是说要避免使用 @ 并不能回答问题。 PHP有时会抛出异常,可以捕获,有时会显示愚蠢的通知,无法捕获。在这种情况下,关闭整个应用程序的错误不是一个合理的解决方案。当场使它们静音也不是理想的,但稍微好一点(特别是对于像 file_exists 或 file_get_contents 这样的情况,它们在发生错误时已经返回 false,因此您不需要通知)。理想情况下,PHP 报告错误的方式不会被破坏,但我们需要处理它。 您应该避免使用@运算符,但有时您需要使用使用它们的库。 @SimonBackx packagist 网站上不乏库。你可能会找到一个更好的。现在已经不是 2011 年了:D【参考方案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,似乎无法从错误处理程序中确定警告是否由带有 @ 前缀的代码触发或如果系统上禁用了错误报告。不过,我希望能够做到这一点,因为我有一个案例,尊重 @ 但不尊重一般错误报告设置是有意义的。是否有一些解决方法? 您可以在代码的开头设置一个变量,并使用该变量来区分上面的// @ sign temporary disabled error reporting。另一种选择是使用ini_get('error_reporting') 来检查ini 文件,但这只有在您调整配置文件中的错误报告时才有效。

以上是关于@错误抑制运算符和set_error_handler的主要内容,如果未能解决你的问题,请参考以下文章

PHP 通知抑制;只有某些情况/方法

这是使用错误抑制运算符的不良做法吗?

[PHP] 报错和“@” - 工作

C++ SPDLOG 编译错误:变量或字段“set_error_handler”声明为无效

PHP set_error_handler() 函数

@ 抑制运算符的运用