为什么PHP错误会打印两次?

40

简介

惊人的是,我在谷歌或SO上找不到这方面的任何信息。当我在PHP中抛出异常时,它会在控制台上打印两次,完整地显示错误消息和堆栈跟踪。第一次打印时,它会显示“PHP致命错误:...”,而第二次只显示“致命错误:...”。我尚未测试Apache插件版本。

示例

为了保密,使用“…”缩短了一些命名空间和路径:

$ php code/com/.../tabular_data.php
PHP Fatal error:  Uncaught exception 'Exception' with message 'File type not supported' in /home/codemonkey/.../tabular_data.php:56
Stack trace:
#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 {main}
  thrown in /home/codemonkey/.../tabular_data.php on line 56
Fatal error: Uncaught exception 'Exception' with message 'File type not supported' in /home/codemonkey/.../tabular_data.php:56 Stack trace: #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 {main} thrown in /home/codemonkey/.../tabular_data.php on line 56

问题

我认为这与stderr和stdout都打印错误有关。无论如何,我该如何礼貌地要求PHP仅打印一次,并最好将其打印到stderr?


版本输出

PHP 5.3.9 (cli) (built: Jan 11 2012 17:09:48)
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.3.0,版权所有(c) 1998-2012 Zend Technologies

代码

http://pastebin.com/iBUGJ2eY
这是能让我出现双重异常的完整代码,其中名称空间和路径已编辑成 foos。请注意,在此安装中,我始终在命令行中获得双重异常。我相信问题出在PHP配置上。


2
有使用任何自定义错误处理程序吗?我使用的是 5.3.9-1~dotdeb.3 版本,似乎无法通过抛出异常来重现此问题。我只能得到第二个消息。 - Linus Kleen
你是否定义了任何自定义错误处理程序?你是否重定向错误输出或类似的操作?请展示一个最小化而完整的脚本,以复现这个问题。 - deceze
被讨论的代码是一个类定义和一个类实例化。异常发生在实例化过程中。这个代码里没有什么花哨的东西。万一你想查看,可以点击这里(http://pastebin.com/iBUGJ2eY)。它短小精悍,但是并不引人注目。出于好奇,我运行了“echo ini_get('error_reporting');” 并得到了 32767。那是怎么回事?难道不应该返回像 E_ALL 这样的字符串吗? - Hubro
1
E_ALL只是E_NOTICEE_WARNING等位掩码的组合。尝试使用print E_ALL;你将得到一个数字,因为它只是一个常量。 - Linus Kleen
2个回答

52

已经复现。第一个错误消息是由log_errors设置引起的,会输出到STDERR

第二个错误消息是由display_errors设置引起的,会输出到STDOUT

这两个设置都可以在运行时更改。因此,为了“礼貌地请求PHP”,只需执行以下操作:

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

5
这让我想起了一篇文章,“PHP:一个糟糕设计的分形” http://t.co/ytXaNjV - Taras
谢谢,这是我需要的答案的一半。 我添加了自己的答案来完善你的信息 ;) - Radon8472
如果我设置了 ini_set('log_errors', 1);ini_set('display_errors', 0); 并从 CLI 运行 PHP 脚本抛出异常,我将看不到任何输出。未捕获的异常消息会在标准输出上输出两次。有什么想法吗?谢谢! - tonix
1
你是什么都没看到还是看到了两次?哪一个? - Linus Kleen

2

Linus Kleen的答案所述,双重消息的原因是display_errors输出到stdout。 我发现自从php 5.2.4以来,即使将display_errors设置为1或"on",这种情况仍会发生。

恢复正常行为的最佳方法是定义一个文件来存储记录的错误,例如添加以下内容:

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

将文件定义到您的php.ini中的error_log,您只会得到一个消息发送到标准输出,这对于测试是必需的。对于生产状态,您可以将display_errors设置为0。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接