处理 @ 错误控制运算符

多年来,许多 PHP 开发人员使用 @ 错误控制运算符来掩盖错误。在使用不可靠的 PHP 库和编写糟糕的代码时尤其如此。不幸的是,这种用法的最终结果只能是传播不良代码!

许多 PHP 开发人员一厢情愿地认为,当他们使用 @ 操作符来阻止错误显示时,问题似乎就神奇地消失了!请相信我:问题并没有消失!在本节中,我们首先考察 @ 操作符的传统用法,然后考察 PHP 8 中 @ 操作符的变化。

有关传统 @ 运算符语法和用法的更多信息,请参阅此文档参考页面: https://www.php.net/manual/en/language.operators.errorcontrol.php

@ 运算符用法

在介绍代码示例之前,我们必须再次强调,我们并不提倡使用这种机制!相反,您应该在任何情况下都避免使用这种机制。如果出现错误信息,最好的解决办法是修复错误,而不是让它保持沉默!

在下面的代码示例中,定义了两个函数。bad() 函数故意触发一个错误。worse() 函数包含一个存在解析错误的文件。请注意,在调用这些函数时,@ 符号会出现在函数名之前,从而抑制错误输出:

// /repo/ch03/php8_at_silencer.php
function bad() {
    trigger_error(__FUNCTION__, E_USER_ERROR);
}
function worse() {
    return include __DIR__ . '/includes/
causes_parse_error.php';
}
echo @bad();
echo @worse();
echo "\nLast Line\n";

在 PHP 7 中,根本没有输出,如下所示:

root@php8_tips_php7 [ /repo/ch03 ]# php php8_at_silencer.php
root@php8_tips_php7 [ /repo/ch03 ]#

值得注意的是,在 PHP 7 中,程序实际上无法继续:我们从未看到最后一行的输出。这是因为,尽管被掩盖了,但还是产生了一个致命错误,导致程序失败。而在 PHP 8 中,致命错误没有被掩盖,如图所示:

root@php8_tips_php8 [ /repo/ch03 ]# php8 php8_at_silencer.php
PHP Fatal error: bad in /repo/ch03/php8_at_silencer.php on
line 5

现在让我们看看 PHP 8 中有关 @ 操作符的另一个不同之处。

@ 运算符和 error_reporting()

error_reporting() 函数通常用于覆盖 php.ini 文件中设置的 error_reporting 指令。然而,该函数的另一个用途是返回最新的错误代码。然而,在 PHP 8 之前的 PHP 版本中存在一个奇怪的例外情况,即如果使用了 @ 操作符,error_reporting() 返回值为 0

在下面的代码示例中,我们定义了一个错误处理程序,当调用该程序时,它会报告收到的错误编号和字符串。此外,我们还会显示 error_reporting() 返回的值:

// /repo/ch03/php8_at_silencer_err_rep.php
function handler(int $errno , string $errstr) {
    $report = error_reporting();
    echo 'Error Reporting : ' . $report . "\n";
    echo 'Error Number : ' . $errno . "\n";
    echo 'Error String : ' . $errstr . "\n";
    if (error_reporting() == 0) {
        echo "IF statement works!\n";
    }
}

与之前一样,我们定义了一个故意触发错误的 bad() 函数,然后使用 @ 操作符调用该函数,如下所示:

function bad() {
    trigger_error('We Be Bad', E_USER_ERROR);
}
set_error_handler('handler');
echo @bad();

在 PHP 7 中,error_reporting() 返回 0,因此输出中会出现 IF statement works!

root@root@php8_tips_php7 [ /repo/ch03 ] #
php php8_at_silencer_err_rep.php
Error Reporting : 0
Error Number : 256
Error String : We Be Bad
IF statement works!

而在 PHP 8 中运行时,error_reporting() 返回最后一个错误的值—​本例中是 4437。当然,if() 表达式也失败了,没有额外的输出。下面是相同代码在 PHP 8 中运行的结果:

root@php8_tips_php8 [ /repo/ch03 ] #
php php8_at_silencer_err_rep.php
Error Reporting : 4437
Error Number : 256
Error String : We Be Bad

PHP 8 中 @ 运算符使用差异的考虑到此结束。

最佳实践:不要使用 @ 错误控制操作符!使用 @ 操作符的目的是抑制错误信息的显示,但您首先需要考虑的是为什么会出现错误信息。使用 @ 操作符只能避免提供问题的解决方案!

总结

本章概述了 PHP 8 在错误处理方面的主要变化,并举例说明了可能出现错误的情况,现在您已了解如何在 PHP 8 中正确处理错误。如果您的代码有可能导致上述任何一种情况,即以前的警告现在变成了错误,那么您的代码就有可能被破解。

同样,虽然第二组错误条件在过去只会产生通知,但现在这些条件同样会导致警告。新的一组警告给了你调整错误代码的机会,防止应用程序陷入严重的不稳定状态。

最后,您还了解了如何强烈反对使用 @ 操作符。在 PHP 8 中,这种语法将不再掩盖致命错误。在下一章中,您将学习如何在 PHP 8 中创建 C 语言结构和直接调用 C 语言函数。