fetch()每次取一行,返回一维数组;fetchall()一次性取全部,返回二维数组;核心区别在于返回行数而非是否返回数组。

fetch() 和 fetchAll() 的核心区别在哪
区别不在“能不能返回数组”,而在于“返回几行”。fetch() 每次只取一行,返回一维数组(或对象);fetchAll() 一次性取全部,直接返回二维数组。如果你要的是“整个结果集转成 PHP 数组”,fetchAll() 是最直白的选择。
常见错误是写成:$row = $stmt->fetch(PDO::FETCH_ASSOC); 然后直接 return $row; —— 这只会返回第一条记录,不是“数组格式的结果集”。
-
fetchAll()返回的是array[0..n][column_name => value],天然适配前端Array.isArray()判断 - 若用
fetch(),必须手动循环 +$result[] = $row;,否则数据被覆盖 -
fetchAll()内存占用略高,但对几百条以内数据无感;超千条建议流式处理(用fetch()配合分页或游标)
PDO::FETCH_ASSOC 是最常用但不是唯一选项
很多人以为 fetchAll(PDO::FETCH_ASSOC) 是默认行为,其实不是:PDO 默认用 PDO::FETCH_BOTH,即同时带数字键和字符串键,容易引发 Notice: Array to string conversion 或 JSON 字段重复。
显式指定模式才能确保结构稳定:
-
PDO::FETCH_ASSOC:只保留列名作键,适合字段名明确、需按名访问的场景 -
PDO::FETCH_NUM:纯数字索引,适合列顺序固定、追求极致性能的导出类逻辑 -
PDO::FETCH_BOTH:慎用,JSON 编码后会出现双份字段(如{"id":1,"0":1}) - 可提前设置全局模式:
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);,之后所有fetch()/fetchAll()都按此生效
query() 和 prepare()/execute() 对返回数组没影响,但影响安全性
无论用 query("SELECT * FROM user") 还是 prepare("SELECT * FROM user WHERE id = ?")→execute([$id]),只要最后调用 fetchAll(),返回的数组结构完全一致。区别只在参数绑定和 SQL 注入防护。
所以选哪个,取决于你的 SQL 是否含用户输入:
- 静态查询(如
"SELECT status FROM config LIMIT 1")→ 直接query(),少写两行 - 含变量(如
"WHERE name = '$name'")→ 必须用prepare()+execute(),否则有注入风险 -
query()返回PDOStatement对象,也能调fetchAll(),别被名字误导
空结果集会返回空数组,但要注意异常捕获
fetchAll() 在查询成功但无数据时,返回 [](空数组),不是 null 或 false。这点很关键——你不需要额外判 if ($result === false),但必须确保 PDO 错误模式已设为异常,否则 SQL 报错会静默失败。
漏掉这步,$stmt = $pdo->query("SELECT * FROM nonexistent_table"); 可能返回 false,再调 fetchAll() 就报 Call to a member function fetchAll() on bool。
- 务必初始化 PDO 时开启异常:
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - 空结果无需特殊处理,
count($result) === 0就够判断 - 如果用了
fetch()循环,记得检查$stmt->rowCount()是否为 0,避免空循环
实际开发中最容易被忽略的,是默认 fetch 模式没重置导致 JSON 输出字段重复,以及没开 PDO::ERRMODE_EXCEPTION 让 SQL 错误吞掉却不报错。这两点不修,调试时会花掉远超预期的时间。











