为啥 PHP 错误会打印两次?

Posted

技术标签:

【中文标题】为啥 PHP 错误会打印两次?【英文标题】:Why are PHP errors printed twice?为什么 PHP 错误会打印两次? 【发布时间】:2012-02-18 14:09:14 【问题描述】:

总结

令人惊讶的是,我在 Google 或 SO 上一无所获。当我在 php 中抛出异常时,它会在我的控制台中出现两次,并带有错误消息和堆栈跟踪。第一次打印时显示“PHP 致命错误:...”,第二次打印时仅显示“致命错误:...”。我没有测试这是Apache插件版本。

示例

为了安全起见,一些命名空间和路径用“...”缩短:

$ php 代码/com/.../tabular_data.php
PHP 致命错误:在 /home/codemonkey/.../tabular_data.php:56 中带有消息“不支持文件类型”的未捕获异常“异常”
堆栈跟踪:
#0 /home/codemonkey/.../tabular_data.php(88): com\...\Tabular_Data->loadFromFile('/home/codemonke...', false)
#1 /home/codemonkey/.../tabular_data.php(95): com\...\Tabular_Data::fromFile('/home/codemonke...')
#2 主要
  在第 56 行的 /home/codemonkey/.../tabular_data.php 中抛出

致命错误:/home/codemonkey/.../tabular_data.php:56 中未捕获的异常“异常”和消息“不支持文件类型”
堆栈跟踪:
#0 /home/codemonkey/.../tabular_data.php(88): com\...\Tabular_Data->loadFromFile('/home/codemonke...', false)
#1 /home/codemonkey/.../tabular_data.php(95): com\...\Tabular_Data::fromFile('/home/codemonke...')
#2 主要
  在第 56 行的 /home/codemonkey/.../tabular_data.php 中抛出

问题

我认为它与 stderr 和 stdout 都打印错误有关。无论如何,我如何很好地要求 PHP 只打印一次,最好打印到 stderr?


版本输出

PHP 5.3.9 (cli)(构建时间:2012 年 1 月 11 日 17:09:48) 版权所有 (c) 1997-2012 PHP Group Zend Engine v2.3.0,版权所有 (c) 1998-2012 Zend Technologies

代码

http://pastebin.com/iBUGJ2eY 这是为我显示双重异常的确切代码,名称空间和路径编辑为 foos。请注意,在此安装中,我总是在命令行中遇到双重异常。我几乎可以肯定问题出在 PHP 配置上。

【问题讨论】:

是否涉及任何自定义错误处理程序?使用5.3.9-1~dotdeb.3 我似乎无法通过抛出异常来重现这一点。我只收到第二条消息。 您是否定义了任何自定义错误处理程序?您是否正在重定向错误输出或类似的东西?请展示一个最小的、完整的脚本来重现这个问题。 有问题的代码是一个类定义和一个类实例化。异常发生在实例化期间。这段代码还没有什么花哨的东西。以防万一你可以check it out here。这是令人印象深刻的不起眼和简短。出于好奇,我跑了echo ini_get('error_reporting');,得到了32767。那是怎么回事?这不应该返回像 E_ALL 这样的字符串吗? E_ALL 只是E_NOTICEE_WARNING 等的位掩码。试试print E_ALL;你会得到一个数字,因为它只是一个常数。 【参考方案1】:

转载了。第一条错误消息是log_errors 设置的结果,并转到STDERR

第二个是display_errors 的结果并转到STDOUT

这两个设置都可以在运行时更改。因此,为了“很好地询问 PHP”,这就足够了:

ini_set('log_errors', 1);
ini_set('display_errors', 0);

【讨论】:

正是我想要的。谢谢你 这让我想起了文章“PHP:糟糕设计的分形”t.co/ytXaNjV THX,这就是我需要的答案的一半。我添加了一个自己的答案来完成您的信息;) 如果我设置 ini_set('log_errors', 1);ini_set('display_errors', 0); 并且我运行我的 PHP 脚本并从 CLI 抛出异常,我看不到任何输出。未捕获的异常消息在标准输出上输出两次。任何想法?谢谢! 没有看到任何东西,或者它显示了两次?是哪个?【参考方案2】:

就像answer of Linus Kleen 中写的那样,出现双重消息的原因是display_errors 转到标准输出。 我发现从 php 5.2.4 开始,当display_errors 设置为 1 或“on”时,甚至会发生这种情况。

要恢复正常行为,最好的方法是定义应存储已记录错误的文件,例如添加这个:

error_log = 'd:/logs/php_error.log'

到你的 php.ini。 定义 error_log 文件后,您只会收到一条消息到标准输出,这是您测试所需的内容。 对于生产状态,您可以将display_errors 设置为 0。

【讨论】:

以上是关于为啥 PHP 错误会打印两次?的主要内容,如果未能解决你的问题,请参考以下文章

为啥这个 sybase 错误会随着查询的任何更改而消失?

为啥我的 pyqt 信号错误会冻结 ui,直到调用另一个 python 函数

为啥密码错误会导致“填充无效,无法删除”?

如果 error_log 指令只是说“error_log”,那么 PHP 错误会记录到哪里?

redux-observable 无法从发出的动作中捕获错误,错误会停止动作流

将弱符号和局部符号链接在一起时,可能的 GCC 链接器错误会导致错误