为什么缺少“require”/“include”调用error_handler一个额外的时间?

时间:2013-07-12 14:23:18

标签: include require php php-internals

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

输出:

  

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

     

Err String:include(/missing_file.php)   [function.include]:无法打开流:没有这样的文件或目录

     

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

     

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

     

//下一阶段:

     

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

     

Err String:include()[function.include]:失败   打开'/missing_file.php'以包含在内   (include_path中= ':/ usr / lib中/ PHP:在/ usr /本地/ LIB / PHP')

     

传递到默认值   处理程序...

     

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

使用require观察到相同的行为。

例如,将第11行更改为require将提供此输出:

  

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

     

Err String:require(/missing_file.php)[function.require]:失败了   open stream:没有这样的文件或目录

     

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

     

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

     

//下一阶段:

     

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

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

1 个答案:

答案 0 :(得分:2)

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

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

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

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

    Check these slides了解有关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,可能是梨或lib目录,以及包含路径你明确设定。
    我已经从this site得到了这个想法,根据我得到的输出,在我看来,这似乎是为什么你看到多个错误的最合理的解释。