我使用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
可能导致错误处理程序的额外调用的原因是什么?
答案 0 :(得分:2)
这很简单,真的。 PHP的生命周期由4个不同的阶段组成:
要解析您的代码,需要在第一阶段提取所有包含/需要的文件,以将代码转换为有意义的表达式。您的文件不存在,因此会发出警告
接下来,编译阶段遇到相同的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得到了这个想法,根据我得到的输出,在我看来,这似乎是为什么你看到多个错误的最合理的解释。