
本文详解为何使用 pdo 的 `prepare()` + `execute()` 后调用 `fetch()` 会返回布尔值而非数组,导致“trying to access array offset on value of type bool”错误,并提供安全、兼容的解决方案。
你遇到的错误——PHP Warning: Trying to access array offset on value of type bool——根本原因在于混淆了 PDO 和 MySQLi 的 API 行为。
在你的代码中:
$result = $conn->prepare("SELECT * FROM bustracker ORDER BY id ASC");
$result->execute();
for($i=0; $row = $result->fetch(); $i++){ // ❌ 错误:PDO::fetch() 返回关联/索引数组,但此处循环逻辑有隐患看似无误,实则存在两个关键问题:
$result->fetch() 本身是合法的(PDO 支持),但你的 $conn 很可能实际是 MySQLi 连接对象(例如 mysqli),而非 PDO 实例。
✅ mysqli::prepare()->execute() 返回布尔值;
✅ mysqli_stmt::fetch() 需配合 bind_result() 使用,不能直接 $stmt->fetch() 并当数组用;
❌ 而你却像对待 mysqli_result::fetch_array() 一样直接访问 $row['id'],导致 $row 是 false(布尔值),引发类型错误。-
即便 $conn 是 PDO,for 循环中 $row = $result->fetch() 的写法虽可运行,但未做空结果集校验,且易因逻辑混乱导致意外行为。
立即学习“PHP免费学习笔记(深入)”;
✅ 正确做法(推荐使用 MySQLi 面向对象风格,与你当前环境最匹配):
query("SELECT * FROM bustracker ORDER BY id ASC");
// ✅ 检查查询是否成功,并确保有数据
if ($result && $result->num_rows > 0) {
while ($row = $result->fetch_assoc()) { // ← 关键:用 fetch_assoc() 获取关联数组
$id = $row['id'];
?>
Edit
Delete
No records found. ";
}
?>? 关键改进说明:
- ✅ ->query() + ->fetch_assoc() 是 MySQLi 的标准组合,明确返回关联数组,可安全访问 $row['id'];
- ✅ 添加 if ($result && $result->num_rows > 0) 防御性判断,避免空结果集导致循环异常;
- ✅ 使用 htmlspecialchars() 输出所有动态内容,防止 XSS 攻击;
- ✅ urlencode() 处理 URL 参数,保障特殊字符(如空格、&)安全传输;
- ✅ 删除冗余的 $i 计数器——while 循环天然按行迭代,无需手动索引。
⚠️ 如果你坚持使用 PDO(更安全、支持预处理):
请确认 $conn 是 new PDO(...) 实例,并改用:
$stmt = $conn->prepare("SELECT * FROM bustracker ORDER BY id ASC");
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { // ← 显式指定 FETCH_ASSOC
// ... 同上输出逻辑
}? 总结:
错误本质是 API 误用——把 MySQLi 的语句对象当成了 PDO,或未正确使用其结果集方法。优先采用 query() + fetch_assoc() 组合,简洁、直观、容错强。同时务必对所有用户可控输出进行 HTML 转义,兼顾功能与安全。










