PHP的try/catch无法捕获mysql_*函数及默认模式下mysqli/PDO的错误,因其触发的是E_WARNING等PHP错误而非Throwable异常;需分别设置PDO::ATTR_ERRMODE为EXCEPTION、mysqli_report为STRICT等启用异常模式才能被捕获。

PHP 本身无法用 try/catch 捕获传统 MySQL 扩展(如 mysql_query)产生的警告或错误——它们属于 PHP 错误,不是异常。
为什么 try/catch 抓不到 mysql_error() 类错误
因为 mysql_* 函数(已废弃)和默认模式下的 mysqli、PDO 都是通过触发 PHP 错误(E_WARNING 等)来报告问题,而 try/catch 只捕获实现了 Throwable 的异常对象(Exception 或 Error 子类)。
-
mysql_connect()失败时抛出E_WARNING,不是异常 -
mysqli_query()在默认模式下也只发警告,不抛异常 -
PDO在PDO::ERRMODE_SILENT或PDO::ERRMODE_WARNING下同样不会进入catch
让 try/catch 真正生效:必须启用异常模式
只有将数据库扩展配置为“抛出异常”,try/catch 才能起作用。关键在驱动层设置:
-
PDO:调用
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION) -
MySQLi 面向对象风格:设置
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT)(需在连接前启用) - MySQLi 过程式风格:不支持直接开启异常模式,建议改用面向对象写法
示例(PDO):
立即学习“PHP免费学习笔记(深入)”;
$pdo = new PDO($dsn, $user, $pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 必须这行
try {
$pdo->query("SELECT * FROM nonexistent_table");
} catch (PDOException $e) {
echo "数据库异常:" . $e->getMessage();
}
mysql_error() 已彻底淘汰,别再用
mysql_* 系列函数自 PHP 7.0 起已被移除,任何依赖 mysql_error() 或 mysql_errno() 的代码在 PHP 7+ 上会直接报 Fatal error: Uncaught Error: Call to undefined function mysql_error()。
- 迁移路径只有两条:改用
mysqli或PDO - 若还在维护老项目且 stuck 在 PHP 5.6,也应禁用
display_errors并改用mysqli_error($link)或$mysqli->error -
mysql_error()的返回值是字符串,不能被catch,只能靠if+die()或手动日志记录
生产环境必须关掉错误显示,但要保留异常捕获逻辑
即使启用了 PDO::ERRMODE_EXCEPTION,如果 display_errors = On,错误堆栈仍会暴露敏感信息(如表名、路径、SQL 片段)。正确做法是:
- 在入口脚本顶部加
ini_set('display_errors', 'Off') - 确保
log_errors = On且error_log指向可写文件 - 异常捕获块里不要直接输出
$e->getTraceAsString()给用户 - 对用户只返回泛化提示(如“操作失败,请稍后重试”),详细日志另存
最容易被忽略的一点:PDO 异常模式在连接成功后才生效;如果 new PDO() 本身失败(如用户名密码错),它仍会触发 E_WARNING 或 PDOException(取决于 PHP 版本),此时需用 try 包住整个初始化过程,而不是只包查询。



















