php的try-catch无法捕获notice和warning,因其属于错误机制而非异常体系;需用set_error_handler转为errorexception才能捕获,且e_error等致命错误须用register_shutdown_function+error_get_last()兜底。

try-catch 为什么捕获不到 Notice 和 Warning
PHP 的 try/catch 默认只捕获 Throwable 及其子类(如 Exception、Error),而 E_NOTICE、E_WARNING 属于错误(error)机制,不是异常,不会触发 catch 分支。
典型现象:echo $undefined_var; 在 try 块里执行,页面照样报 Notice: Undefined variable,且完全不进任何 catch。
- 必须提前调用
error_reporting(E_ALL),否则低级别错误可能被静默忽略 - 要用
set_error_handler()拦截并手动转成ErrorException才能被catch捕获 -
set_error_handler对E_ERROR等致命错误无效——它们会直接终止脚本,无法被 handler 拦截
正确转换示例:
set_error_handler(function($severity, $message, $file, $line) {
if (!(error_reporting() & $severity)) return;
throw new ErrorException($message, 0, $severity, $file, $line);
});
PDO 查询失败却没进 catch,是不是漏了配置
默认情况下,PDO 不抛异常,而是返回 false 并触发 E_WARNING(比如表不存在、SQL 语法错)。这意味着你写了 try { $pdo->query(...); } 却完全没反应,不是语法错,是 PDO 根本没开启异常模式。
- 连接时必须显式设置
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION - 仅在
new PDO()构造时传选项不够,还要确保后续的PDOStatement行为也受控 - 强烈建议同时设
PDO::ATTR_EMULATE_PREPARES => false,否则某些 SQL 错误(如字段名错)会被预处理模拟层吞掉,不触发异常
连接示例:
$pdo = new PDO($dsn, $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
]);
catch(Exception $e) 还是 catch(Throwable $e)?
PHP 7+ 引入了 Throwable 接口,统一涵盖 Exception 和 Error(如 TypeError、ParseError)。只写 catch(Exception $e) 会漏掉所有 Error 类型——比如函数参数类型不符、json_encode 传了资源句柄,这些都抛 TypeError,但不会进 Exception 分支。
- 生产环境建议优先用
catch(Throwable $e),避免未捕获的Error导致脚本崩溃 - 若需区分处理,可多级 catch:
catch(TypeError $e)→catch(Exception $e)→catch(Throwable $e)(顺序不能颠倒) -
finally中如果有return,会覆盖catch块的返回值,这点极易被忽略
致命错误(E_ERROR)根本没法 catch,怎么兜底
try/catch 对 E_ERROR、E_PARSE、E_COMPILE_ERROR 等完全无效——它们发生在 Zend 引擎层面,不走异常分发流程。唯一可行的兜底方式是 register_shutdown_function + error_get_last()。
- 必须在脚本最开始注册 shutdown 函数,否则可能来不及执行
- 只对已发生的致命错误有效,不能阻止它发生,也不能恢复执行
- 检查
error_get_last()返回的type是否属于致命类(如E_ERROR),再做日志或告警
兜底示例:
register_shutdown_function(function() {
if ($error = error_get_last()) {
if (in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
error_log('FATAL: ' . $error['message'] . ' in ' . $error['file'] . ':' . $error['line']);
}
}
});
真正容易被忽略的是:错误转异常那一步必须和 error_reporting 级别对齐,且 set_error_handler 无法覆盖所有错误类型;而 PDO 那种“看着像异常实则静默失败”的行为,在没有日志或调试输出时,几乎无法察觉。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











