在您看来,使用@运算符来抑制PHP中的错误/警告是否有效,而您可能正在处理错误?
如果是这样,你会在什么情况下使用它?
欢迎使用代码示例。
编辑:回复者注意。我不打算关闭错误报告,但是,例如,通常的做法是使用
@fopen($file);
然后再检查......但是你可以通过
来摆脱@if (file_exists($file))
{
fopen($file);
}
else
{
die('File not found');
}
或类似的。
我想问题是 - 是否有任何@HAS用于抑制错误,不能以任何其他方式处理?
答案 0 :(得分:116)
注意:首先,我意识到99%的PHP开发人员使用错误抑制操作符(我曾经是其中之一),所以我期待任何看到这个的PHP开发人员不同意。
在您看来,使用@运算符来抑制PHP中的错误/警告是否有效,而您可能正在处理错误?
简答:
不!
更正确的答案:
我不知道,因为我不知道一切,但到目前为止,我还没有遇到过这是一个很好的解决方案。
为什么不好:
在我认为使用PHP大约7年的时候,我已经看到了由错误抑制操作员引起的无休止的调试痛苦,并且从未遇到过无法避免的情况。
问题在于您要阻止错误的代码,目前可能只会导致您看到的错误;但是,当您更改受抑制的行所依赖的代码或其运行的环境时,该行有可能尝试从您尝试忽略的错误中输出完全不同的错误。那么如何追踪未输出的错误?欢迎调试地狱!
我花了很多年才意识到由于错误的原因,我每隔几个月就浪费了多少时间。最经常(但不是唯一)这是在安装第三方脚本/应用程序/库之后,在开发人员环境中没有错误,但不是我的,因为php或服务器配置差异或缺少依赖性,这通常会立即输出错误警告问题是什么,但不是当开发者添加魔法时。
替代方案(取决于情况和期望的结果):
处理您所知道的实际错误,以便如果一段代码会导致某个错误,那么它就不会在该特定情况下运行。但我认为你得到了这个部分而你只是担心最终用户会看到错误,这就是我现在要解决的问题。
对于常规错误,您可以设置错误处理程序,以便在您查看页面时以您希望的方式输出错误处理程序,但对最终用户隐藏并记录,以便您知道用户正在触发的错误。
对于致命错误,在php.ini中将display_errors
设置为关闭(您的错误处理程序仍会被触发)并启用错误记录。如果你有一个开发服务器和一个实时服务器(我推荐),那么在开发服务器上不需要这一步,因此你仍然可以调试这些致命错误,而不必诉诸于查看错误日志文件。甚至还有一个trick using the shutdown function会向您的错误处理程序发送大量致命错误。
总结:
请避免它。可能有一个很好的理由,但我还没有看到一个,所以直到那天我认为(@)错误抑制操作符是邪恶的。
如果您想了解更多信息,可以在PHP手册中阅读my comment on the Error Control Operators page。
答案 1 :(得分:24)
我会压制错误并处理它。否则,您可能会遇到 TOCTOU 问题(检查时间,使用时间。例如,在file_exists返回true之后,但在fopen之前,文件可能会被删除)。
但我不会压制错误让它们消失。这些更好看。
答案 2 :(得分:18)
是抑制是有道理的。
例如,如果无法打开文件,fopen()
命令将返回FALSE
。这没关系,但它也会产生一条PHP警告信息。通常你不需要警告 - 你自己会检查FALSE
。
事实上,PHP manual特别建议在这种情况下使用@!
答案 3 :(得分:12)
如果您不希望在使用fopen()等函数时抛出警告,则可以抑制错误但使用异常:
try {
if (($fp = @fopen($filename, "r")) == false) {
throw new Exception;
} else {
do_file_stuff();
}
} catch (Exception $e) {
handle_exception();
}
答案 4 :(得分:7)
我从不允许自己使用'@'...期间。
当我在代码中发现'@'的使用时,我添加了注释,使其在使用时和使用它的函数周围的docblock中都非常明显。由于这种错误抑制,我也被“追逐鬼”调试所困扰,我希望通过在找到它时突出显示它的用法,使下一个人更容易。
如果我希望自己的代码在本机PHP函数遇到错误时抛出异常,并且'@'似乎是最简单的方法,我会选择做其他相同的事情结果,但是(再次)在代码中显而易见:
$orig = error_reporting(); // capture original error level
error_reporting(0); // suppress all errors
$result = native_func(); // native_func() is expected to return FALSE when it errors
error_reporting($orig); // restore error reporting to its original level
if (false === $result) { throw new Exception('native_func() failed'); }
这只是编写的代码:
$result = @native_func();
但我更喜欢让我的抑制需要非常明显,为了跟随我的糟糕的调试灵魂。
答案 5 :(得分:6)
应该避免错误抑制,除非你知道你可以处理所有条件。
这可能比最初看起来要困难得多。
你真正应该做的是依靠php的“error_log”作为你的报告方法,因为你不能依赖用户查看页面来报告错误。 (你还应该禁止php显示这些错误)
那么至少你会得到一份关于系统中出现问题的综合报告。
如果您真的必须处理错误,可以创建自定义错误处理程序
http://php.net/set-error-handler
然后你可以发送异常(可以处理)并做一些事情来报告管理中的奇怪错误。
答案 6 :(得分:5)
大多数人都不理解错误信息的含义 不开玩笑。其中大部分都是。
他们认为错误信息都是一样的,说“出了问题!” 他们懒得读它 虽然它是错误信息中最重要的部分 - 不仅仅是它已被提出的事实,而是它的含义。它可以告诉你 出了什么问题。错误消息是为了帮助,而不是打扰你“如何隐藏它?”问题。这是新手网络编程世界中最大的误解之一。
因此,不应该呕吐错误消息,而应该读取它所说的内容。它不仅有一个“找不到文件”的值。可能存在数千种不同的错误:permission denied
,save mode restriction
,open_basedir restriction
等等。每个人都需要采取适当行动但如果你唠叨它,你永远不会知道发生了什么!
OP正在搞错误报告错误处理,但这是非常大的区别!
错误处理是针对用户的。 “发生的事情”就足够了。
虽然错误报告是针对程序员的,但他们迫切需要知道发生了什么。
因此,永远不要唠叨错误消息。程序员记录,用户处理。
答案 7 :(得分:3)
有没有办法压制php.ini警告和错误?在这种情况下,您只能调试更改标志而不是尝试发现哪个@隐藏了问题。
答案 8 :(得分:3)
我真正需要使用它的唯一地方是eval功能。 eval的问题在于,当由于语法错误而无法解析字符串时,eval不返回false,而是抛出错误,就像在常规脚本中出现解析错误一样。为了检查存储在字符串中的脚本是否可解析,您可以使用以下内容:
$script_ok = @eval('return true; '.$script);
AFAIK,这是最优雅的方式。
答案 9 :(得分:3)
使用@有时会适得其反。根据我的经验,您应该始终在php.ini中关闭错误报告或调用
error_reporting(0);
在生产网站上。这样,当您处于开发阶段时,您可以注释掉该行并保持错误以便进行调试。
答案 10 :(得分:2)
我使用它的一个地方是套接字代码,例如,如果你有一个超时设置,如果你不包含@,你就会得到一个警告,即使它没有得到一个数据包也是有效的。
$data_len = @socket_recvfrom( $sock, $buffer, 512, 0, $remote_host, $remote_port )
答案 11 :(得分:2)
PHP中的某些函数将发出E_NOTICE
(例如unserialize函数)。
(对于PHP versions 7+,捕获该错误的一种可能方法是将所有已发布的错误转换为异常,而不是让其发布E_NOTICE
。我们可以如下更改异常错误处理程序:
function exception_error_handler($severity, $message, $file, $line) {
throw new ErrorException($message, 0, $severity, $file, $line);
}
set_error_handler('exception_error_handler');
try {
unserialize('foo');
} catch(\Exception $e) {
// ... will throw the exception here
}
答案 12 :(得分:1)
你不想压制所有内容,因为它会降低你的脚本速度。
是的,在php.ini和脚本中都有一种方法可以删除错误(但只有当你在实时环境中并从php中记录错误时才这样做)
<?php
error_reporting(0);
?>
你可以阅读this获取关闭它的php.ini版本。
答案 13 :(得分:0)
如果您正在使用自定义错误处理功能并想要抑制错误(可能是已知错误),请使用此方法。在这种情况下使用'@'不是一个好主意,因为如果设置了错误处理程序,它不会抑制错误。
写3个函数并像这样调用。
# supress error for this statement
supress_error_start();
$mail_sent = mail($EmailTo, $Subject, $message,$headers);
supress_error_end(); #Don't forgot to call this to restore error.
function supress_error_start(){
set_error_handler('nothing');
error_reporting(0);
}
function supress_error_end(){
set_error_handler('my_err_handler');
error_reporting('Set this to a value of your choice');
}
function nothing(){ #Empty function
}
function my_err_handler('arguments will come here'){
//Your own error handling routines will come here
}
答案 14 :(得分:0)
今天我遇到了一个问题,这是一个很好的例子,说明何时可能要至少临时使用@运算符。
长话短说,我发现登录信息(纯文本格式的用户名和密码)写在错误日志跟踪中。
有关此问题的更多信息。
登录逻辑属于其自己的一类,因为系统应该提供不同的登录机制。由于服务器迁移问题,发生了错误。该错误将整个跟踪转储到错误日志中,包括密码信息!一种方法以用户名和密码作为参数,因此trace将所有内容忠实地写入错误日志。
这里的长期解决方法是重构所述类,而不是将用户名和密码用作2个参数,例如,使用包含这2个值的单个数组参数(在这种情况下,trace将为参数写出Array)。还有其他解决此问题的方法,但这是一个完全不同的问题。
无论如何。跟踪消息很有用,但在这种情况下是完全有害的。
当我注意到跟踪输出时,我吸取了教训:有时暂时抑制错误消息是一种有用的停止间隙措施,以避免进一步的伤害。
在我看来,我不认为这是糟糕的班级设计案例。错误本身是由PDOException触发的(时间戳问题从MySQL 5.6移至5.7),PHP刚将其默认转储为错误日志。
通常,出于其他注释中解释的所有原因,我不使用@运算符,但是在这种情况下,错误日志使我迅速采取了措施,直到问题得到正确解决。
答案 15 :(得分:0)
我认为是使用@ 抑制错误的有效用例。
我有两个系统,一个运行 PHP 5.6.something,另一个运行 PHP 7.3.something。我想要一个可以在它们两个上正常运行的脚本,但有些东西在 PHP 5.6 中不存在,所以我使用了像 random_compat 这样的 polyfill。
最好使用内置函数,所以我的代码如下所示:
if(function_exists("random_bytes")) {
$bytes = random_bytes(32);
} else {
@include "random_compat/random.php"; // Suppress warnings+errors
if(function_exists("random_bytes")) {
$bytes = random_bytes(32);
} else if(function_exists('openssl_random_pseudo_bytes')) {
$bytes = openssl_random_pseudo_bytes(4);
} else {
// Boooo! We have to generate crappy randomness
$bytes = substr(str_shuffle(str_repeat('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',64)),0,32);
}
}
回退到 polyfill 不应产生任何错误或警告。在尝试加载必要的 polyfill 后,我正在检查该函数是否存在。甚至有后备的后备。以及回退到回退。
无法避免 include
的潜在错误(例如使用 file_exists
),因此唯一的方法是抑制警告并检查它是否有效。至少,在这种情况下。
答案 16 :(得分:0)
我可以想到一种使用情况,用于自动递增一个不存在的数组键。
$totalCars = [];
$totalCars['toyota']++; // PHP Notice: Undefined index: toyota
@$totalCars['toyota']++;
// [
// "toyota" => 2,
// ]
答案 17 :(得分:-1)
我在尝试加载HTML文件以作为DOMDocument对象进行处理时使用它。如果HTML中存在任何问题...而且哪个网站没有至少一个 ... DOMDocument-&gt; loadHTMLFile()如果你没有用它来抑制它就会抛出错误@。这是唯一的方法(也许有更好的方法)我曾经成功地用PHP创建HTML scraper。