我尖叫,你尖叫,我们都尖叫着@

@是一个经典的PHP运算符,意味着禁止在本地显示金沙上线。它是PHP代码的主食,在65%的PHP存储库中使用:2中的2个存储库,但尚未推荐使用它来避免。

实际上,现在有没有理由仍然使用这个运营商? @非常慢:它实际上在金沙上线处理的最后一刻介入。金沙上线由PHP处理,特别是金沙上线处理程序,@只是抑制任何最终输出。这是什么都不做的。事实上,在呼叫前写一张检查通常更快,以减轻这个问题。

为了了解@现象更好,让’S审查了大量的情况,考虑发生的事情以及替代方案是什么。

过时的功能

这里,@用于隐藏过时的消息。在阶段‘deprecated warning’, array_key_exists works as usual, yet emits a warning to help prepare for the upcoming exception. In PHP 8.0, this call will emit a TypeError exception, and stop. Until then, a simple PHP Deprecated is emitted, and the code will not stop.

<?php
  array_key_exists($key, $variable);
?>

简单的替代方案是配置PHP.ini指令ERROR_REPORTING而无需折旧通知。然而,在开发阶段,将通知激活总是更好的:这是了解到那时的最佳时刻,并修复它们。

在这种情况下,最好的替代方法是检查该数组 钥匙 存在()实际应用于数组,而不是对象。这是以不同的方式实现的:使用IS_ARRAY()函数使用IF /那条条件;使用(阵列)铸造甚至是一个类型。

即将到来的特点

弃用功能通常在实际删除之前警告。如果代码正在尝试使用即将推出的PHP功能,则没有早期警告。

例如,这也是即将到来的新常量,@ent_disallowed的情况,它出现在PHP 5.4中。在此之前,使用它是不可能的,因为htmlentities()将无法识别它。

在这种情况下,条件常量(或其他结构)定义,具有中性值,从而消除误差。如果可以模拟该功能,则更好。

用于伐木目的

看看这种情况:

<?php
@trigger_error('The use of the "default" keyword is deprecated. Use the real template name instead.', E_USER_DEPRECATED);
?>

让’了解它:trigger_error()发出金沙上线,然后立即发出金沙上线,@隐藏它。这是什么明显的悖论?

trigger_error.() is used here to fill a log, and @ is here to avoid such notice to be displayed in the GUI of the application. The deprecation should be hidden, indeed. Since the application uses error manager, the most logical way to log something is to emit an error, with the right level : here, E_USER_DEPRECATED.

Among the alternative for this situation, one may use assert(). Those assertion produce an error, and may be removed with a php.ini directive. That way, the code is useful during the development phase, with its message, and removed in production. No more need for @.

另一种替代方案是切换到PHP 8.0属性(除非您在PHP 8.0出版物之前读取本文)。

抑制eval()中的金沙上线?

邪恶之王,eval()绝对是金沙上线抑制的经典候选者。问题与eval()本身无关:毕竟,将一个字符串传递为参数不是真正的挑战。

真正的挑战是字符串内的PHP代码,它将冒出调用上下文。

<?php
@eval('trigger_error("Yeah");');
?>

eval()通常很容易避免,特别是使用现代PHP版本。你可以检查一下 PHP使用eval()的土地 获取帮助何时或如何删除其使用情况。

很高兴记住,应该将eval()呼叫放在Try / Catch块中,以捕获汇编问题。至少,这将是eval()的一个问题,以及任何入侵者的反馈较少。

持续金沙上线

使用系统调用的使用,例如使用shell_exec()。使用以下代码,目标是避免显示系统金沙上线。它失败了。

<?php
@shell_exec('ls non_existent_folder');
?>

一旦执行shell,金沙上线通道就用于shell中生成的金沙上线。此频道独立于PHP金沙上线管理,但与PHP金沙上线通道合并。在这里,添加@将不会阻止金沙上线显示。

一个替代方案是检查shell命令,并应用适应的验证。在这里,情况很简单:文件存在()并且是dir()给我们的方法来避免呼叫shell_exec()及其金沙上线。

另一种替代方案是将金沙上线通道与shell中的输出通道合并。像这样 :

<?php
shell_exec('ls non_existent_folder 2&>1');
?>

现在,金沙上线被引导到shell_exec()的结果,而不立即显示。

跳过支票

@通常是一个迹象,即跳过了存在的存在检查。另一种方式,代码对缺失的值感到舒适。

这通常是沉默值的情况:

<?php
echo @$raList[$cnt];
?>

Here, the index is controlled by a variable. So, the index may be missing, or the variable $cnt may contain an invalid or unexpected index.

Note also that @ is applied to the whole expression, so $raList might also be non-existing, in that case. It is not possible to distinguish where the error occurs, between the variables or the index. We’LL稍后再看到该功能。

@是ISSET(),空()或更新的替代方案。 ISSET()检查实际存在的值,而空()检查它是否存在并且不是伪造的。 null coalesce运算符??提供默认值,以防第一个表达式为null,而抑制金沙上线消息。

<?php
if (isset($raList[$cnt])) {
    echo $raList[$cnt];
} else { 
    echo 'default';
}

echo @$raList[$cnt] ?? 'default';
?>

具有副作用的金沙上线抑制的另一个例子是setCookie()或标头()。在任何输出发生之前都必须使用它们。你可能遇到了臭名昭着的金沙上线‘headers already sent’.

<?php
    @setcookie('DEBUG', true);
?>

@ oderations of to致电标题()。虽然其他示例实现了它们给出的任务,但SetCookie()和标题()失败。 @使这个沉默,这是一个长虫狩猎的开始。

虽然检查数据存在是一件好事,同样适用于许多外部实体,例如文件或远程应用程序。例如 :

<?php
@file_get_contents($object->url);
@unlink($object->_tempFileName);
?>

如果缺少即可删除的文件,请解开()发出警告。所以,存在检查不是ISSET(),而是一个文件_EXIST()调用。另一方面,在实际到达之前,远程URL难以检查。在这种情况下,@可能是最简单的本地解决方案。

涵盖整个文件

@抑制在分配的整个表达式期间金沙上线消息。大多数情况下,这是一个表达式,所以下面的两个字符串实际上隐藏了相同的金沙上线:

<?php
echo @strtoupper(substr(1234567, 2, 3));
echo strtoupper(@substr(1234567, 2, 3));
?>

@在应用程序包含()时获得扩展的电源,及其堂兄弟:包括一次(),要求(),需要一次()。金沙上线抑制也应用于包括的所有代码。这是有趣的,特别是当包含是常量表达式时,没有任何变量或函数调用。

<?php
@include './functions.php'
?>

当@ AIMS at检查包含的文件实际上是可用的,如缓存的情况,那么file_exists()检查会删除@上的使用情况。

非常罕见的是,金沙上线抑制是针对整个文件的抑制,所以在File_exists()检查后@可能是多余的。

最常见的功能与@

什么是最沉默的PHP功能?以下是经典列表,按字母顺序排列(无需使竞争对手,右?)。

关于文件的函数是最常见的,因为涉及的文件可能或不可用于执行。

列表 ()是右手表达式的经典’t包含足够的元素以填充左侧表达式。 preg_match()有点令人惊讶,就像与指令相关的函数一样。 define()示出了创建常量的战术后备。

一个特例

在研究本文的同时,一个特殊情况落在雷达上。这个简单的preg_match()呼叫,在exakat中’s code.

<?php
@preg_match($regex, '');
?>

它实际上是分析规则的核心 无效的正则表达式。此分析从代码中提取正则表达式,并检查它是否是有效的正则表达式。这里的目标是让preg_match()检测到正则表达式编译金沙上线,捕获它们,隐藏它们,然后报告它。

显然,它是@运营商的一个非常适用的用法,但值得一提。

根本没有理由

最后,总有一些创造性的@。他们很少见,但总是有趣的寻找。人们只能想知道他们如何在代码中结束。

<?php
@phpversion( ); 
$a = @[];
$b = @@$sql;

?>

让’s Stop Using @

@已在最近的PHP版本中重新开始,以确保它不起作用’t捕获指令的任何金沙上线‘display_errors’ wouldn’T。鉴于在绝大多数情况下,PHP有工具来检查任何资源,数据或对象及其存在,最后用例是@是当一个人写入代码时。

Indeed, while writing the stats, I ended up using @$stats[$function]++;, to collect usage of functions. It was not tempting to check the existence of the index, and, moreover, as you read it, this code is now gone. Otherwise, it would have been extended with a clean check. That’s快速和脏@和持久代码之间的实际区别。