为什么“失踪”;要求“/";包括“;再调用errorhandler一次


Why does missing "require" / "include" call error_handler an extra time?

我使用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
?>

输出:

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

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

正在传递到默认处理程序。。。

//默认处理程序不执行任何操作,即使error_reporting不是零

//下一阶段:

在自定义错误处理程序中

错误字符串:include()[function.includ]:失败正在打开"/missing_file.php"以进行包含(include_path='.:/usr/lib/php:/usr/local/lib/php')

传递到默认处理程序。。。

警告:include()[function.includ]:打开失败'/missing_file.php'以供包含在里面/home/yccom/public_html/apr/test.php在线11

CCD_ 2也观察到了相同的行为。

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

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

错误字符串:require(/messing_file.php)[function.request]:未能开放流:没有这样的文件或目录

正在传递到默认处理程序。。。

//默认处理程序不执行任何操作,即使errorreporting是非零

//下一阶段:

致命错误:require()[function.request]:在/home/yccom/public_html/apr/test.php上打开必需的'/missing_file.php'失败线路11

是什么原因导致了错误处理程序的额外调用?

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

  1. 正在分析
  2. 汇编
  3. 正在扫描
  4. 执行

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

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

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

查看这些幻灯片,了解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目录,以及您明确设置的include路径
我从这个网站上得到了这样做的想法,根据我得到的输出,这似乎是对为什么你会看到多个错误最合理的解释。