PHP Conference Japan 2024

PDOStatement::fetch

(PHP 5 >= 5.1.0, PHP 7, PHP 8, PECL pdo >= 0.1.0)

PDOStatement::fetch 获取结果集中的下一行

描述

public PDOStatement::fetch(int $mode = PDO::FETCH_DEFAULT, int $cursorOrientation = PDO::FETCH_ORI_NEXT, int $cursorOffset = 0): mixed

从与 PDOStatement 对象关联的结果集中获取一行。 mode 参数决定 PDO 如何返回该行。

参数

mode

控制如何将下一行返回给调用方。此值必须是 PDO::FETCH_* 常量之一,默认为 PDO::ATTR_DEFAULT_FETCH_MODE 的值(默认为 PDO::FETCH_BOTH)。

  • PDO::FETCH_ASSOC:返回一个由结果集中返回的列名作为索引的数组

  • PDO::FETCH_BOTH(默认):返回一个由结果集中返回的列名和 0 索引的列号作为索引的数组

  • PDO::FETCH_BOUND:返回 true 并将结果集中列的值分配给使用 PDOStatement::bindColumn() 方法绑定到的 PHP 变量

  • PDO::FETCH_CLASS:返回请求类的新的实例,将结果集的列映射到类中的命名属性,并在之后调用构造函数,除非也提供了 PDO::FETCH_PROPS_LATE。如果 mode 包含 PDO::FETCH_CLASSTYPE(例如 PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE),则类的名称由第一列的值确定。

  • PDO::FETCH_INTO:更新请求类的现有实例,将结果集的列映射到类中的命名属性

  • PDO::FETCH_LAZY:组合 PDO::FETCH_BOTHPDO::FETCH_OBJ,并返回一个 PDORow 对象,该对象在访问时创建对象属性名称。

  • PDO::FETCH_NAMED:返回一个与 PDO::FETCH_ASSOC 具有相同形式的数组,但如果有多个列具有相同的名称,则该键引用的值为该行中所有具有该列名的值的数组

  • PDO::FETCH_NUM:返回一个由结果集中返回的列号作为索引的数组,从列 0 开始

  • PDO::FETCH_OBJ:返回一个匿名对象,其属性名称对应于结果集中返回的列名

  • PDO::FETCH_PROPS_LATE:当与 PDO::FETCH_CLASS 一起使用时,在从相应的列值分配属性之前调用类的构造函数。

cursorOrientation

对于表示可滚动游标的 PDOStatement 对象,此值确定将返回给调用方的行。此值必须是 PDO::FETCH_ORI_* 常量之一,默认为 PDO::FETCH_ORI_NEXT。要为 PDOStatement 对象请求可滚动游标,必须在使用 PDO::prepare() 准备 SQL 语句时将 PDO::ATTR_CURSOR 属性设置为 PDO::CURSOR_SCROLL

cursorOffset

对于表示可滚动游标的 PDOStatement 对象,其中 cursorOrientation 参数设置为 PDO::FETCH_ORI_ABS,此值指定要获取的结果集中行的绝对编号。

对于表示可滚动游标的 PDOStatement 对象,其中 cursorOrientation 参数设置为 PDO::FETCH_ORI_REL,此值指定相对于调用 PDOStatement::fetch() 之前游标位置的行。

返回值

此函数成功时的返回值取决于获取类型。在所有情况下,如果失败或没有更多行,则返回 false

错误/异常

如果属性 PDO::ATTR_ERRMODE 设置为 PDO::ERRMODE_WARNING,则发出级别为 E_WARNING 的错误。

如果属性 PDO::ATTR_ERRMODE 设置为 PDO::ERRMODE_EXCEPTION,则抛出 PDOException

示例

示例 #1 使用不同的获取样式获取行

<?php
$sth
= $dbh->prepare("SELECT name, colour FROM fruit");
$sth->execute();

/* 使用 PDOStatement::fetch 样式 */
print "PDO::FETCH_ASSOC: ";
print
"将下一行作为以列名作为索引的数组返回\n";
$result = $sth->fetch(PDO::FETCH_ASSOC);
print_r($result);
print
"\n";

print
"PDO::FETCH_BOTH: ";
print
"将下一行作为以列名和数字作为索引的数组返回\n";
$result = $sth->fetch(PDO::FETCH_BOTH);
print_r($result);
print
"\n";

print
"PDO::FETCH_LAZY: ";
print
"将下一行作为具有列名作为属性的 PDORow 对象返回\n";
$result = $sth->fetch(PDO::FETCH_LAZY);
print_r($result);
print
"\n";

print
"PDO::FETCH_OBJ: ";
print
"将下一行作为具有列名作为属性的匿名对象返回\n";
$result = $sth->fetch(PDO::FETCH_OBJ);
print
$result->name;
print
"\n";
?>

以上示例将输出

PDO::FETCH_ASSOC: Return next row as an array indexed by column name
Array
(
    [name] => apple
    [colour] => red
)

PDO::FETCH_BOTH: Return next row as an array indexed by both column name and number
Array
(
    [name] => banana
    [0] => banana
    [colour] => yellow
    [1] => yellow
)

PDO::FETCH_LAZY: Return next row as a PDORow object with column names as properties
PDORow Object
(
    [name] => orange
    [colour] => orange
)

PDO::FETCH_OBJ: Return next row as an anonymous object with column names as properties
kiwi

示例 #2 使用可滚动游标获取行

<?php
function readDataForwards($dbh) {
$sql = 'SELECT hand, won, bet FROM mynumbers ORDER BY BET';
$stmt = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
$stmt->execute();
while (
$row = $stmt->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_NEXT)) {
$data = $row[0] . "\t" . $row[1] . "\t" . $row[2] . "\n";
print
$data;
}
}
function
readDataBackwards($dbh) {
$sql = 'SELECT hand, won, bet FROM mynumbers ORDER BY bet';
$stmt = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_LAST);
do {
$data = $row[0] . "\t" . $row[1] . "\t" . $row[2] . "\n";
print
$data;
} while (
$row = $stmt->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_PRIOR));
}

print
"正向读取:\n";
readDataForwards($conn);

print
"反向读取:\n";
readDataBackwards($conn);
?>

以上示例将输出

Reading forwards:
21    10    5
16    0     5
19    20    10

Reading backwards:
19    20    10
16    0     5
21    10    5

示例 #3 构造顺序

当通过 PDO::FETCH_CLASS 获取对象时,首先分配对象属性,然后调用类的构造函数。如果也提供了 PDO::FETCH_PROPS_LATE,则此顺序将反转,即首先调用构造函数,然后分配属性。

<?php
Person
{
private
$name;

public function
__construct()
{
$this->tell();
}

public function
tell()
{
if (isset(
$this->name)) {
echo
"我是 {$this->name}.\n";
} else {
echo
"我还没有名字。\n";
}
}
}

$sth = $dbh->query("SELECT * FROM people");
$sth->setFetchMode(PDO::FETCH_CLASS, 'Person');
$person = $sth->fetch();
$person->tell();
$sth->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, 'Person');
$person = $sth->fetch();
$person->tell();
?>

以上示例将输出类似以下内容

I am Alice.
I am Alice.
I don't have a name yet.
I am Bob.

参见

添加注释

用户贡献的注释 22 条注释

91
terry at bitsoup dot com
18 年前
警告
在处理空数据集时,fetch() 不会遵循 SQL-92 SQLSTATE 标准。

它不会将错误代码类设置为 20 以指示“未找到数据”,而是返回类 00 表示成功,并将 NULL 返回给调用方。

这也阻止了异常机制的触发。

程序员需要在任何 fetch*() 之后显式地为空结果集编写测试,而不是依赖于 RDBMS 的默认行为。

我尝试将其记录为错误,但它被驳回为“按预期工作”。只是提醒一下。
77
yarco dot wang at gmail dot com
10 年前
如果没有记录,此函数也将返回 false。
我认为这不太好……
37
henry at henrysmith dot org
13 年前
有人已经指出 SQLite 驱动程序不支持 PDO::CURSOR_SCROLL。还值得注意的是,MySQL 驱动程序也不支持它。

事实上,如果您尝试对 MySQL 语句使用可滚动游标,则 PDO::FETCH_ORI_ABS 参数和传递给 fetch() 的偏移量将被静默忽略。fetch() 将按正常方式运行,按照从数据库中获取到的顺序返回行。

一开始这实际上是一个非常令人困惑的行为。即使只是作为此页面上的用户添加的注释,也绝对值得记录。
27
gergo at gergoerdosi dot com
11 年前
在 while 循环中使用 PDO::FETCH_COLUMN 时,仅在 while 语句中使用该值是不够的,如许多示例所示

<?php
while ($row = $stmt->fetch(PDO::FETCH_COLUMN)) {
print
$row;
}
?>

如果 5 行的值分别为 1 2 0 4 5,则上面的 while 循环将在第三行停止,仅打印 1 2。解决方法是显式测试 false

<?php
while (($row = $stmt->fetch(PDO::FETCH_COLUMN)) !== false) {
print
$row;
}
?>

或使用带有 fetchAll() 的 foreach

<?php
foreach ($stmt->fetchAll(PDO::FETCH_COLUMN) as $row) {
print
$row;
}
?>

两者都将正确打印 1 2 0 4 5。
20
lod
16 年前
获取返回的第一条条目的快速单行代码。这对于非常基本的查询很有用。

<?php
$count
= current($db->query("select count(*) from table")->fetch());
?>php
13
public at grik dot net
14 年前
获取对象时,默认情况下会在填充字段后调用类的构造函数。

PDO::FETCH_PROPS_LATE 用于更改行为并使其按预期工作 - 在对象字段填充数据之前调用构造函数。

示例

<?php
$a
= $PDO->query('select id from table');
$a->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, 'ClassName');
$obj = $a->fetch();
?>

http://bugs.php.net/bug.php?id=53394
10
Typer85 at gmail dot com
14 年前
这是使用 PDO SQLite 驱动程序的开发人员的快速说明

PDO SQLite 驱动程序不支持游标,因此在使用 PDO SQLite 驱动程序时,使用 PDO::CURSOR_SCROLL 属性将不起作用。例如

<?php

// 假设 $Handle 是一个 PDO 句柄。
$Statement = $Handle->query( $sqlStatement , array( PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL ) );

?>

更糟糕的是,即使错误模式设置为抛出异常,PDO::prepare 也不会在无法准备查询时抛出异常,而是会返回布尔值 False!

我不仅认为这是一个糟糕的设计选择,而且很遗憾的是,手册中没有任何地方记录了这一点——事实上,手册没有明确说明哪些驱动程序支持哪些属性,哪些不支持,因此开发人员只能玩猜谜游戏。

希望这能为一些开发人员节省一些麻烦。

祝你好运,
2
paulf at quillandmouse dot com
4 年前
一位之前的发帖者指出,当没有结果时,此函数返回 NULL。这是错误的。此函数返回一个空数组。fetchAll() 返回相同的内容。

此外,文档指定了“失败”时会发生什么,但没有说明什么构成“失败”。“失败”可能是函数没有返回结果的情况;也就是说,查询“失败”了。但是,“失败”显然是指 PDO 错误函数会显示“失败”的情况,例如非法的 SQL 语法或对不存在的表的查询等。空结果不是“失败”。也许这对其他人来说很明显,但对我来说并非如此。
9
Gerard van Beek
17 年前
如果您要为记录使用类的新的实例,您可以使用

<?php
include_once("user.class");
$sth = $db->prepare("SELECT * FROM user WHERE id = 1");

/* 自动创建实例 */
$sth->setFetchMode( PDO::FETCH_CLASS, 'user');
$sth->execute();
$user = $sth->fetch( PDO::FETCH_CLASS );
$sth->closeCursor();
print (
$user->id);

/* 或自己创建实例并使用 */
$user= new user();
$sth->setFetchMode( PDO::FETCH_INTO, $user);
$sth->execute();
$user= $sth->fetch( PDO::FETCH_INTO );
$sth->closeCursor();
print (
$user->id);
?>
3
[email protected]
10 年前
由于 MySQL 目前不支持使用游标,因此在使用 PDO 访问 MySQL 数据库时,$cursor_offset 功能无法工作。

如果您尝试任意访问 MySQL 数据库记录集中特定记录或记录组,可以考虑使用 SELECT 语句的 LIMIT 子句来实现此目的,例如 LIMIT 5,3 返回第 6、7 和第 8 条记录 - 从索引 5(即第 6 条记录)开始的 3 条记录。
3
[email protected]
19 年前
我还可以补充一点,如果您使用 PDO::FETCH_CLASS,则在对象上设置数据_之后_会运行构造函数。
3
[email protected]
19 年前
如果您想使用 PDO::FETCH_CLASS,则需要先使用 setFetchMode 进行设置,如下所示
$stmt->setFetchMode( PDO::FETCH_CLASS, 'classType', array( 'parameters to constructor' );
$object = $stmt->fetch( PDO::FETCH_CLASS );
如果您省略此操作,PHP 将出现段错误。
1
Black Knight
8 年前
这只是一个关于第二个参数 -cursor_oriantation- 的提醒。

PDO::FETCH_ORI_NEXT :-
获取结果集中的下一行。仅对可滚动游标有效。

PDO::FETCH_ORI_PRIOR :-
获取结果集中的上一行。仅对可滚动游标有效。

PDO::FETCH_ORI_FIRST :-
获取结果集中的第一行。仅对可滚动游标有效。

PDO::FETCH_ORI_LAST :-
获取结果集中的最后一行。仅对可滚动游标有效。

PDO::FETCH_ORI_ABS :-
通过结果集中的行号获取请求的行。仅对可滚动游标有效。

PDO::FETCH_ORI_REL :-
通过结果集中游标的当前位置的相对位置获取请求的行。仅对可滚动游标有效。
0
Drew
4 年前
当使用将提取模式设置为 FETCH_CLASS 的 PDOStatement 时,如果未找到任何行,则 fetch 将返回 false。
1
marcini
17 年前
在使用预处理语句和 MySQL 时,请注意 fetch()(我不知道其他数据库的情况)。Fetch 不会关闭游标,也不会允许您发送任何其他查询,即使您的结果集只有一行。
如果您使用 $statement->fetch(),则之后还必须使用 $statement->closeCursor(),才能执行另一个查询。
或者,您可以使用 $statement->fetchAll() 而无需 $statement->closeCursor()。
-2
Alex
13 年前
似乎如果您使用 $statement->query() 执行 INSERT 语句,然后执行 $statement->fetch(),您将收到一个异常,提示:SQLSTATE[HY000]: General error。
-1
[email protected]
16 年前
我花了几个小时试图找出如何使用 PDO 操作 BLOB 字段。

请记住,您不能使用以下方式检索 BLOB 数据

<?php
$sql
= 'SELECT * FROM sometable LIMIT 1';
$stmt = $dbh->prepare($sql);
$stmt->execute();
$stmt->setAttribute(PDO::FETCH_ASSOC);
$row = $stmt->fetch();

$myFile = $row['file'];
?>

而应该尝试以下方法

<?php
$sql
= "SELECT mime, file FROM sometable LIMIT 1";
$stmt = $dbh->prepare($sql);
$stmt->execute();

$stmt->bindColumn(1, $mime,);
$stmt->bindColumn(2, $file, PDO::PARAM_LOB);

$stmt->fetch();

header('Content-type: '.$mime);
print
$file;

?>
-2
tastro
10 年前
请注意,通过这种方式,“提取模式”将被“覆盖”,并且不会应用 PDO::FETCH_PROPS_LATE

<?php
$sth
= $db->prepare("SELECT * FROM user WHERE id = 1");
$sth->setFetchMode( PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, 'user');
$sth->execute();
$user = $sth->fetch( PDO::FETCH_CLASS );
$sth->closeCursor();
?>

相反,如果您想使用 setFetchMode() 方法设置提取模式,则应将 fetch() 方法的参数区域留空,如下所示

<?php
$sth
= $db->prepare("SELECT * FROM user WHERE id = 1");
$sth->setFetchMode( PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, 'user');
$sth->execute();
$user = $sth->fetch();
$sth->closeCursor();
?>
-3
[email protected]
12 年前
我可以使用 PDO::FETCH_COLUMN 检索结果的第一列。
$ps->fetch( PDO::FETCH_COLUMN );
在使用 PHP 5.3.10 的 Postgresql 上运行。
-2
[email protected]
19 年前
请注意,对于 PHP 5.1 之前的版本,PDO 类中不包含 fetch 常量。
-4
josh
16 年前
请注意,PDO::ATTR_STRINGIFY_FETCHES 对于 MySQL 驱动程序不起作用。MySQL 将始终返回字符串,因为这是核心 mysql PHP 扩展的行为。请参阅 http://bugs.php.net/bug.php?id=44341
-4
[email protected]
8 年前
使用 PDO::FETCH_LAZY 时要小心。它添加了一个名为 queryString 的额外字段。我不确定这是否是错误。我在 Debian Jessie 中使用版本 5.6.17。

查询:'select 1,2,3'

$row=$smt->fetch(PDO::FETCH_OBJ);
var_dump($row);

object(stdClass)#6 (3) {
["1"]=>
string(1) "1"
["2"]=>
string(1) "2"
["3"]=>
string(1) "3"
}

$row=$smt->fetch(PDO::FETCH_LAZY);
var_dump($row);

object(PDORow)#3 (4) {
["queryString"]=>
string(12) "select 1,2,3"
["1"]=>
string(1) "1"
["2"]=>
string(1) "2"
["3"]=>
string(1) "3"
}
To Top