SQL语法错误时PDOException未被捕获的问题排查
问题原因及解决方案
核心问题:PDO未启用异常模式
你的代码无法进入catch块,是因为PDO默认错误模式不会抛出异常,只会返回错误结果或触发PHP警告。因此query()执行出错时不会抛出PDOException,自然无法被catch捕获。
解决步骤
1. 开启PDO异常模式
在初始化PDO连接的代码中,添加错误模式配置:
// 初始化PDO连接时加入这行设置 $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
开启后,PDO执行SQL出错时会主动抛出PDOException,catch块就能正常捕获错误。
2. 修复SQL注入风险(同时解决类型错误问题)
你当前直接拼接$val到SQL的写法存在严重SQL注入漏洞,还会导致id=a这类类型不匹配的错误(数据库会把a解析为列名而非值)。改用预处理语句可同时解决这两个问题:
public function read($tableName, $conditions = []) { $con = $this->container->get('connection'); // 可选:验证表名合法性,防范表名注入风险 // if (!in_array($tableName, $allowedTables)) { throw new InvalidArgumentException('Invalid table name'); } if (empty($conditions)) { $query = "SELECT * FROM $tableName"; $stmt = $con->query($query); } else { $whereClauses = []; $params = []; foreach ($conditions as $key => $val) { // 使用占位符?替代直接拼接值 $whereClauses[] = "$key = ?"; $params[] = $val; } $where = implode(' AND ', $whereClauses); $query = "SELECT * FROM $tableName WHERE $where"; $stmt = $con->prepare($query); // PDO自动处理数据类型绑定与转换 $stmt->execute($params); } try { $data = $stmt->fetchAll(PDO::FETCH_ASSOC); $con = null; return $data; } catch(PDOException $e) { $con = null; return [ 'status-code' => 500, 'error' => $e->errorInfo()[0], 'message' => $e->getMessage() ]; } }
补充说明
- 预处理语句会自动处理值的类型转换,比如把字符串
'a'传入数字类型的id字段时,数据库会抛出类型不匹配的异常,该异常会被catch块正常捕获。 - 永远不要直接拼接用户输入到SQL语句中,预处理是防御SQL注入的标准方案。
内容的提问来源于stack exchange,提问作者mikael khalil
相关产品推荐
相关产品推荐

