Parse error 即 E_PARSE,是说代码在语法解析时发现了错误,会报错并退出解析。
注意,现在还只是解析,代码没有被载入 Zend Engine 解释,所以你的代码还没被执行就已经报错退出了,注册的 set_error_handler / register_shutdown_function 也就没什么作用了。
要理解 PHP 去执行一个脚本的流程,语法解析 -- 解释执行 -- 结束退出。如果最基本的语法解析都没通过,会直接丢给你 E_PARSE 的错误并退出执行,也就不会开始 解释执行 了。
而且看你的代码能感觉出你对 php 的错误处理也不是很清楚。
1、set_error_handler 只能捕捉 E_WARING & E_NOTICE & E_DEPRECATED & E_USER_* & 部分 E_STRICT 级的错误。语法错误 E_PARSE 是没办法用它捕获的。
2、try ... catch 只能捕获 E_PARSE & E_ERROR 级的 ERROR (还有一些其他的,E_CORE_WARNING E_CORE_NOTICE E_COMPILE_WARNING E_COMPLE_NOTICE 等,不常见)
所以 try ... catch 和 set_error_handler 可以互补,这样就能捕获所有的常见错误了。
而且要注意,被 try ... catch 或 set_error_handler(在不返回 false 的前提下) 捕获后的错误,是不会再被 PHP 做标准错误处理,error_reporting,display_errors 都是标准错误处理的设定。即便你 error_reporting(0),关闭了 PHP 标准的错误处理监听,try ... catch 和 set_error_handler 依然能捕捉到错误,而且不会退出执行(set_exception_handler 在捕获异常后就终止执行了, try ... catch 不会)。
至于你故意写 0$a 这种语法级的错误,可以被捕获处理,但需要一些技巧,代码结构需要改为如下,我就不借用你的代码了:
// 要保证一个 try ... catch 的上下文可以运行起来
try {
// 语法检查并不会载入并执行后续要包含的文件
// 即便包含的文件中有语法错误 也不影响本脚本的语法检查
// 解析无误,开始执行,执行到此处时,已经是在 try ... catch 的上下文里了
// 在 module_has_synatx_errors.php 里你写上你的 0$a; 就好
require_once __DIR__ . '/module_has_synatx_errors.php'
} catch (\ERROR $error) {
// 可以捕捉 E_PARSE & E_ERROR 的错误
var_export($error);
}
//module_has_synatx_errors.php
0$a;
运行结果
ParseError::__set_state(array(
'message' => 'syntax error, unexpected \'$a\' (T_VARIABLE)',
'string' => '',
'code' => 0,
'file' => '......\module_has_synatx_errors.php',
'line' => 2,
'trace' => array(
),
'previous' => null,
))
这样就捕捉到了。