用PHP中的@运算符抑制错误
我们认为在PHP中使用@运算符来抑制错误/警告是否有效,而我们可能正在处理该错误?
如果是这样,我们将在什么情况下使用它?
欢迎使用代码示例。
编辑:答复者注意。我不想关闭错误报告功能,但是,例如,通常的做法是使用
@fopen($file);
然后再检查...但是我们可以通过执行以下操作来消除@
if (file_exists($file)) { fopen($file); } else { die('File not found'); }
或者类似。
我想问题是,@ HAS是否有任何地方可以用来阻止错误,并且不能以其他任何方式处理?
解决方案
是的,压制是有道理的。
例如,如果无法打开文件,则" fopen()"命令返回" FALSE"。很好,但是它还会产生一条PHP警告消息。通常,我们不需要警告-我们会自己检查" FALSE"。
实际上,PHP手册特别建议在这种情况下使用@!
有没有办法抑制来自php.ini的警告和错误?在这种情况下,我们只能调试仅更改标志,而不尝试发现哪个@隐藏了问题。
我们不想抑制所有操作,因为它会使脚本运行变慢。
是的,在php.ini和脚本中都可以删除错误(但是仅当我们处于活动环境中并从php登录错误时才可以这样做)。
<?php error_reporting(0); ?>
我们可以阅读有关关闭它的php.ini版本的信息。
除非我们知道可以处理所有情况,否则应避免错误抑制。
这可能比起初看起来要难得多。
我们真正应该做的是依靠php的" error_log"作为报告方法,因为我们不能依靠用户查看页面来报告错误。 (并且我们还应该禁用php以免显示这些错误)
然后,至少我们将获得有关系统中所有错误的全面报告。
如果我们确实必须处理错误,则可以创建一个自定义错误处理程序
http://php.net/set-error-handler
然后,我们可以发送异常(可以处理),并做任何需要向管理部门报告奇怪错误的事情。
我在尝试加载HTML文件以作为DOMDocument对象进行处理时使用它。如果HTML中有任何问题...并且哪个网站没有至少一个问题...如果我们不使用@禁止显示,则DOMDocument-> loadHTMLFile()将引发错误。这是我成功地在PHP中创建HTML抓取工具的唯一方法(也许有更好的方法)。
使用@有时会适得其反。以我的经验,我们应该始终在php.ini中关闭错误报告或者致电
error_reporting(0);
在生产现场。这样,当我们在开发中时,只需注释掉该行,并使错误可见即可进行调试。
我使用它的一个地方是在套接字代码中,例如,如果我们设置了超时设置,则即使不获取数据包也是有效的,但如果不包含@,也会收到警告。
$data_len = @socket_recvfrom( $sock, $buffer, 512, 0, $remote_host, $remote_port )
如果我们不希望在使用fopen()之类的函数时发出警告,则可以抑制该错误,但可以使用异常:
try { if (($fp = @fopen($filename, "r")) == false) { throw new Exception; } else { do_file_stuff(); } } catch (Exception $e) { handle_exception(); }
我会抑制该错误并进行处理。否则,我们可能会遇到TOCTOU问题(检查时间,使用时间。例如,在file_exists返回true之后但在fopen之前,文件可能会被删除)。
但是我不会仅仅抑制错误以使它们消失。这些更好地可见。
注意:首先,我认识到99%的PHP开发人员都使用错误抑制运算符(我曾经是其中之一),所以我希望看到这一点的所有PHP开发人员都不同意。
In your opinion, is it ever valid to use the @ operator to suppress an error/warning in PHP whereas you may be handling the error?
简短答案:
不!
更长的正确答案:
我不知道,因为我不了解所有事情,但是到目前为止,我还没有遇到过一个很好的解决方案。
为什么不好:
在我认为使用PHP大约7年的时间里,我已经看到了由错误抑制运算符引起的无尽调试痛苦,并且从未遇到过不可避免的情况。
问题是我们正在抑制错误的那段代码当前可能仅导致我们看到的错误。但是,当我们更改被禁止的行所依赖的代码或者运行它的环境时,该行很有可能会尝试输出与我们尝试忽略的错误完全不同的错误。那么,如何找到未输出的错误呢?欢迎调试地狱!
我花了很多年才意识到由于被抑制的错误而使我每两个月浪费了多少时间。大多数情况下(但非排他性地),这是在安装了第三方脚本/应用程序/库之后,该脚本在开发人员环境中没有错误,但是由于php或者服务器配置的差异或者缺少依赖关系(通常会立即输出错误)而无法获取提醒问题出在什么地方,但不会在开发人员添加魔术@时发出警告。
备选方案(取决于情况和预期结果):
处理我们所知道的实际错误,以便如果一段代码将导致某个错误,则该代码不会在特定情况下运行。但是我认为我们已经掌握了这一部分,并且我们只是担心最终用户会看到错误,这就是我现在要解决的问题。
对于常规错误,我们可以设置一个错误处理程序,以便在查看页面时以所需的方式输出错误,但对最终用户隐藏并记录下来,以便我们知道用户触发了哪些错误。
对于致命错误,请在php.ini中将" display_errors"设置为" off"(错误处理程序仍被触发),并启用错误记录功能。如果我们同时具有开发服务器和实时服务器(建议使用),则在开发服务器上无需执行此步骤,因此我们仍然可以调试这些致命错误,而不必求助于错误日志文件。使用关闭功能甚至还可以技巧性地向错误处理程序发送大量致命错误。
总之:
请避免。可能有一个很好的理由,但是我还没有看到一个理由,所以直到那一天,我认为(@)错误抑制运算符是有害的。
如果需要更多信息,可以在PHP手册的"错误控制运算符"页面上阅读我的评论。
我绝不允许自己使用'@'...句点。
当我在代码中发现" @"的用法时,无论是在使用时还是在使用该功能的文档块中,我都添加了注释,以使其清晰可见。由于这种错误抑制,我也被"追赶幽灵"调试所困扰,我希望通过在找到它时突出显示它的用法来使下一个人更轻松。
如果我想让自己的代码在本机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();
但是我宁愿让我的压制变得非常明显,因为跟在我后面的调试精神很差。
我真正需要使用的唯一地方是eval函数。 eval的问题在于,当由于语法错误而无法解析字符串时,eval不会返回false,而是会引发错误,就像在常规脚本中出现解析错误一样。为了检查存储在字符串中的脚本是否可解析,我们可以使用类似以下内容的方法:
$script_ok = @eval('return true; '.$script);
AFAIK,这是执行此操作的最优雅的方法。
如果我们使用的是自定义错误处理功能,并且想抑制错误(可能是已知错误),请使用此方法。在这种情况下,使用'@'不是一个好主意,因为如果设置了错误处理程序,它将不会抑制错误。
编写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 }
大多数人不理解错误消息的含义。
别开玩笑了。他们中的大多数。
他们认为错误消息都是一样的,并说:"出问题了!"
他们不花心地阅读它。
虽然它是错误消息的最重要部分,但不仅是它已被提出的事实,而且是含义。它可以告诉我们出了什么问题。错误消息只是为了帮助,而不是让我们"如何隐藏它?"困扰着我们。问题。这是新手Web编程世界中最大的误解之一。
因此,与其阅读错误信息,不如阅读错误内容。它不仅具有一个"找不到文件"值。可能有成千上万种不同的错误:"权限被拒绝","保存模式限制"," open_basedir限制"等。每个人都需要采取适当的措施。但是,如果我们作呕,我们将永远不会知道发生了什么!
OP将错误报告与错误处理搞混了,尽管有很大的不同!
错误处理是针对用户的。在这里"发生了什么"就足够了。
虽然错误报告是针对程序员的,但他们迫切需要知道肯定会发生什么。
因此,切勿阻塞错误消息。两者都为程序员记录下来,并为用户处理。