warning是运行时非中断性问题,脚本继续执行;fatal error直接终止脚本,不执行后续代码,二者触发机制根本不同。

PHP 中 warning 和 fatal error 的触发机制完全不同
警告(warning)是运行时非中断性问题,脚本继续执行;致命错误(fatal error)直接终止脚本,不执行后续任何代码。根本区别不在“严重程度”,而在 PHP 解析/执行阶段的处理路径:warning 属于 E_WARNING 级别,由 Zend 引擎在运行期发出但不打断控制流;fatal error(如 E_COMPILE_ERROR、E_ERROR)会触发 Zend 的“致命中止流程”,跳过所有用户注册的错误处理器(除非是 set_error_handler 未覆盖的类型),直接调用 zend_bailout。
如何用 error_reporting 控制 warning 是否显示,但对 fatal error 无效
error_reporting 可以开关 warning 显示或记录,但对大多数 fatal error 完全无效——因为它们发生在错误报告机制启动之后、甚至绕过它。比如 require 'missing.php' 抛出的 Fatal error: Uncaught Error: Failed opening required,无论 error_reporting(0) 还是 ini_set('display_errors', '0') 都拦不住。
-
error_reporting(E_ALL & ~E_WARNING)能隐藏 warning,但不影响 fatal error 输出 -
ini_set('display_errors', '0')只抑制输出,不阻止 fatal error 发生或日志记录 - 真正能“捕获”部分 fatal error 的只有
register_shutdown_function+error_get_last(),但它只能事后检查,无法阻止中止
用 set_error_handler 捕获 warning,但 catch 不到 fatal error
set_error_handler 默认只接管 E_WARNING、E_NOTICE 等非致命级别。传入 E_ALL 也不会让它处理 E_ERROR 或 E_PARSE ——PHP 文档明确写死:这些错误“cannot be handled by a user-defined error handler”。常见误操作是以为加个 error_reporting(E_ALL) 就能一并捕获,结果发现 call_undefined_function() 依然直接崩掉,handler 根本没被调用。
- 正确做法:把 warning 相关逻辑放
set_error_handler里,比如记录、格式化输出 - 致命错误兜底必须用
register_shutdown_function,且要立刻检查error_get_last()返回值是否为NULL - 注意:
parse error(语法错误)连 shutdown function 都不触发,只能靠预检(如php -l file.php)
实际调试时怎么一眼分清 warning 还是 fatal error
看错误信息开头的关键词和 PHP 版本行为。PHP 7+ 把很多过去是 fatal error 的情况改成了可捕获的 Throwable(比如 TypeError),但传统 Fatal error: 前缀仍是硬分界线。
立即学习“PHP免费学习笔记(深入)”;
- Warning 开头一定是
Warning:(英文环境)或中文“警告:”,后面跟文件行号,脚本继续跑 - Fatal error 开头固定是
Fatal error:或Parse error:,末尾常带in ... on line ...,且没有“继续执行”的迹象 - PHP 7+ 的
Uncaught TypeError看似像 fatal,实则是未被捕获的异常,可用try/catch拦,不属于传统 fatal error 机制
最易忽略的是:某些 fatal error(如内存耗尽 Fatal error: Allowed memory size exhausted)不会触发 register_shutdown_function,因为 Zend 已经彻底放弃当前执行上下文。这时候只能靠监控日志或外部进程检测。











