在PHP项目开发中,数据库查询是几乎绕不开的环节,而查询执行之后如何把结果集中的数据取出来,是许多初学者容易混淆的地方。PHP提供了两套主流的数据库扩展:mysqli和PDO,它们各自都有多种fetch方法,返回的数据格式各不相同,适用的场景也不一样。本文将系统梳理这些获取结果集的方法,并结合代码示例分析它们之间的区别和使用技巧。

一、使用mysqli获取结果集的四种方式
mysqli扩展针对查询结果提供了四个常用的取值方法:fetch_row()、fetch_assoc()、fetch_array()和fetch_object()。它们每次调用都只返回一行数据,因此通常需要配合循环来遍历整个结果集。
fetch_row()返回一个索引数组,下标从0开始,适合字段较少、顺序固定的查询;fetch_assoc()返回关联数组,通过字段名作为键来访问,可读性更好,是实际开发中使用最多的方式;fetch_array()可以看作前两者的合体,默认同时返回索引和关联两种下标;fetch_object()则把一行数据封装成对象,用箭头符号访问属性。
<?php
// 连接数据库
$conn = new mysqli('localhost', 'root', '123456', 'test');
$conn->set_charset('utf8mb4');
// 执行查询
$result = $conn->query('SELECT id, username, email FROM users');
// 方式一:fetch_assoc 返回关联数组
while ($row = $result->fetch_assoc()) {
echo $row['username'] . '<br>';
}
// 方式二:fetch_row 返回索引数组
while ($row = $result->fetch_row()) {
echo $row[0] . ' - ' . $row[2] . '<br>';
}
// 方式三:fetch_object 返回对象
while ($obj = $result->fetch_object()) {
echo $obj->email . '<br>';
}
// 释放结果集
$result->free();
$conn->close();
?>需要注意的是,fetch_array()如果不指定参数,返回的数组中每列数据会出现两次(一次索引下标、一次关联下标),内存开销接近翻倍。因此在明确知道需要哪种格式时,建议显式传入MYSQLI_ASSOC或MYSQLI_NUM常量,或者直接使用对应的专用方法,这样既节省内存又避免了歧义。
二、PDO的fetch与fetchAll用法
PDO作为PHP官方推荐的数据库抽象层,提供了更加灵活的结果集获取方式。核心方法是fetch()和fetchAll(),其中fetch()每次取一行,fetchAll()一次性把所有行装进一个二维数组。它们的第一个参数可以指定获取模式,常用的有PDO::FETCH_ASSOC、PDO::FETCH_NUM、PDO::FETCH_OBJ和PDO::FETCH_BOTH。
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8mb4', 'root', '123456');
$stmt = $pdo->prepare('SELECT id, username FROM users WHERE status = :status');
$stmt->execute([':status' => 1]);
// 逐行获取,使用关联数组模式
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo $row['username'] . PHP_EOL;
}
// 一次性获取全部结果
$list = $stmt->fetchAll(PDO::FETCH_ASSOC);
print_r($list);
// 还有一种很实用的模式:FETCH_COLUMN 直接取出某一列的值数组
$names = $pdo->query('SELECT username FROM users')
->fetchAll(PDO::FETCH_COLUMN);
?>两种获取方式各有优劣:fetchAll()写法简洁,拿到数组后可以随意传递和二次处理,但会把整个结果集一次性加载进内存,如果查询返回几十万行数据,很容易导致内存溢出;fetch()配合循环则是一种流式读取,内存中始终只保存当前一行,处理大数据量时更加安全。另外,PDO还支持在实例化或调用setAttribute()时设置默认的获取模式,这样可以避免每次都重复传入模式参数。
还有一个容易被忽略的实用模式是PDO::FETCH_KEY_PAIR,它可以把两列的结果直接转成键值对数组,例如把用户ID和用户名组成一个映射表,一行代码就能完成,比手动循环拼接数组简洁得多。
三、结果集获取的常见陷阱与优化技巧
第一个常见问题是忘记释放资源。虽然脚本执行结束后PHP会自动回收,但在长连接或者循环执行大量查询的场景下,及时调用free()或closeCursor()可以避免内存持续增长。特别是PDO中复用同一个连接执行多条语句时,必须先释放上一个语句的光标,否则可能报错。
第二个问题是SQL注入风险。获取结果集之前首先要保证查询本身是安全的,永远不要直接把用户输入拼接进SQL字符串,应该使用预处理语句加参数绑定。这不仅是安全规范,也能让重复查询获得语句缓存带来的性能提升。
第三个问题是判断查询结果是否为空。不少人习惯用if ($result)来判断,但实际上查询成功返回的对象即使没有数据也是真值。正确做法是先检查num_rows(mysqli)或rowCount()、fetch()的返回值(PDO),或者干脆取完数组后用empty()判断。
最后在性能方面,如果只需要知道行数而不需要具体数据,尽量在SQL层面使用COUNT()让数据库完成统计,而不是把整个结果集取回PHP再count(),后者的网络传输和内存开销要大得多。遵循这些技巧,可以让结果集的获取既规范又高效。
PHP结果集mysqli fetchPDO fetch修改时间:2026-09-03 01:09:05