2

我有一个使用set_error_handler. 当我试图包含一个不存在的文件时,PHP 调用 error_handler 的次数超出了它应有的次数:

<?php
error_reporting(E_ALL | E_STRICT);
set_error_handler(function($errno, $errstr, $errfile, $errline, $errcontext){
    if(error_reporting() !== 0){
        echo "<br>";
        echo "<br>In Custom Error Handler...";
        echo "<br>Err String: ", $errstr;
        echo "<br>Passing to Default Handler...";
    }
    return false; // allow default
});
include("/missing_file.php"); // line 11
?>

输出:

在自定义错误处理程序中... // 这是额外的错误处理程序调用

错误字符串:包含(/missing_file.php)[function.include]:无法打开流:没有这样的文件或目录

传递给默认处理程序...

// 默认处理程序什么也不做,即使 error_reporting 不为零

// 下一阶段:

在自定义错误处理程序中...

错误字符串:include() [function.include]:无法打开 '/missing_file.php' 以包含 (include_path='.:/usr/lib/php:/usr/local/lib/php')

传递给默认处理程序...

警告:include() [function.include]:未能打开“/missing_file.php”以包含在 第11行的/home/yccom/public_html/apr/test.php中

观察到相同的行为require

例如,将第 11 行更改为require将给出以下输出:

在自定义错误处理程序中... // 这是额外的错误处理程序调用

错误字符串:需要(/missing_file.php)[function.require]:无法打开流:没有这样的文件或目录

传递给默认处理程序...

// 默认处理程序什么也不做,即使 error_reporting 不为零

// 下一阶段:

致命错误:require() [function.require]:无法在第11行的/home/yccom/public_html/apr/test.php中打开所需的“/missing_file.php”

什么可能导致错误处理程序的额外调用?

4

1 回答 1

2

这很简单,真的。PHP 的生命周期由 4 个不同的阶段组成:

  1. 解析
  2. 汇编
  3. 扫描
  4. 执行

对于要解析的代码,需要在第一阶段获取包含/需要的所有文件,以将代码转换为有意义的表达式。您的文件不存在,因此会发出警告。
接下来,编译阶段遇到相同的include语句,并尝试将表达式转换为操作码。该文件不存在,因此发出警告。
扫描将代码转换为令牌,这对于丢失的包含文件同样无法完成。
执行时间... 文件因丢失而无法执行。

为什么 PHP 会这样工作?即使文件丢失,犯错误不是很愚蠢吗?
在某种程度上,是的,但是include用于包含对脚本不重要的文件,如果您确实需要该文件的内容,则使用require(但最好是require_once)。正如您所说,后者会发出致命错误,并阻止一切死在其轨道上。如果您的代码依赖另一个文件来运行,这就是应该发生的情况。

require构造发出一个,它在给定的偏移量(失败语句所在的行)处E_COMPILER_ERROR有效地停止编译器(与 不同)。__halt_compilerrequire

查看这些幻灯片以获取有关 4 个主要阶段中每个阶段的更多详细信息。

您的代码发出四个警告的原因仅仅是因为 PHP 尝试包含该文件四次。尝试从命令行运行脚本,但使用strace

$ strace -o output.txt php yourScript.php

打开输出文件,查看 Zend 引擎的内部结构。特别注意看起来像这样的行:

lstat("/your/path/./file.php", 0x50113add8355) = -1//0x5... ~= 0xsomeaddress

您将看到 PHP 去哪里寻找文件:它的所有include_path目录,cwd, /usr/share/php,可能是 pear 或 lib 目录,以及您明确设置的包含路径。我已经从这个站点
得到了这样做的想法,并且根据我得到的输出,在我看来,这似乎是关于为什么你会看到多个错误的最合理的解释。

于 2013-07-12T14:42:20.083 回答