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();

/* Exercise PDOStatement::fetch styles */
print "PDO::FETCH_ASSOC: ";
print
"Return next row as an array indexed by column name\n";
$result = $sth->fetch(PDO::FETCH_ASSOC);
print_r($result);
print
"\n";

print
"PDO::FETCH_BOTH: ";
print
"Return next row as an array indexed by both column name and number\n";
$result = $sth->fetch(PDO::FETCH_BOTH);
print_r($result);
print
"\n";

print
"PDO::FETCH_LAZY: ";
print
"Return next row as a PDORow object with column names as properties\n";
$result = $sth->fetch(PDO::FETCH_LAZY);
print_r($result);
print
"\n";

print
"PDO::FETCH_OBJ: ";
print
"Return next row as an anonymous object with column names as properties\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
"Reading forwards:\n";
readDataForwards($conn);

print
"Reading backwards:\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
class 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.

参见

添加笔记

用户贡献笔记 26 notes

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 年前
有人已经指出 PDO::CURSOR_SCROLL 不受 SQLite 驱动程序支持。 值得注意的是,它也不受 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
grik dot net 上的 public
13 年前
获取对象时,默认情况下在字段填充后调用类的构造函数。

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
9
gmail dot com 上的 Typer85
14 年前
以下是如何使用 PDO SQLite 驱动程序的开发人员的快速说明

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

<?php

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

?>

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

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

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

祝好,
2
quillandmouse dot com 上的 paulf
4 年前
一位之前的发布者指出,当没有结果时,此函数返回 NULL。这不是真的。此函数返回一个空数组。fetchAll() 返回相同的结果。

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

<?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
yahoo dot co dot uk 上的 lenz_kappov
10 年前
因为 MySQL 目前不支持使用游标,所以 $cursor_offset 功能在使用 PDO 访问 MySQL 数据库时无法工作。

如果你尝试在 MySQL 数据库记录集中任意访问特定记录或记录组,你可能需要考虑使用 SELECT 语句的 LIMIT 子句来实现这一点,例如 LIMIT 5,3 用于返回第 6、7 和 8 条记录 - 从索引 5(即第 6 条记录)开始的 3 条记录。
3
ez dot no 上的 fh
18 年前
我还可以补充一点,如果使用 PDO::FETCH_CLASS,构造函数将在数据设置到对象上之后运行。
3
ez dot no 上的 fh
18 年前
如果你想使用 PDO::FETCH_CLASS,你需要先使用 setFetchMode 设置它,如下所示
$stmt->setFetchMode( PDO::FETCH_CLASS, 'classType', array( '构造函数的参数' );
$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 模式设置为 FETCH_CLASS 的 PDOStatement 时,如果未找到行,fetch 将返回 false。
1
marcini
17 年前
在使用准备好的语句和 MySQL 时要小心使用 fetch()(我不知道其他数据库的情况)。fetch 不会关闭游标,也不会让你发送任何其他查询,即使你的结果集只有一行。
如果你使用 $statement->fetch(),你还需要在之后使用 $statement->closeCursor(),才能执行其他查询。
或者,你可以使用 $statement->fetchAll(),而不需要 $statement->closeCursor()。
-2
Alex
12 年前
似乎如果你使用 $statement->query() 执行 INSERT 语句,然后使用 $statement->fetch(),你将得到一个异常,提示:SQLSTATE[HY000]: General error。
-1
gmail dot com 上的 lozitskiys
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
9 年前
注意,以这种方式,“获取模式”将被“覆盖”,并且不会应用 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();
?>

相反,你应该将 fetch() 方法的参数区域留空,就像这样(如果你想使用 setFetchMode() 方法设置获取模式)

<?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
sumariva at gmail dot com
12 年前
我可以使用 PDO::FETCH_COLUMN 来检索结果的第一列。
$ps->fetch( PDO::FETCH_COLUMN );
在 PHP 5.3.10 的 Postgresql 上运行。
-2
aledmb at gmail dot com
18 年前
请注意,在 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
tim at kooky dot org
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"
}
-6
avinoamr at gmail dot com
18 年前
请注意,使用 FETCH_CLASS 机制不会触发类的构造函数!你必须显式实例化类才能使用它的构造函数行为。
-13
BaBna
16 年前
当你对一行进行 SELECT 查询,并想检查它是否存在时,你不需要计算 fetchAll() 的结果,你只需检查 $result->fetch() 是否为 true 即可。
<?php
$bbnq
= sprintf("SELECT login
FROM users
WHERE id = %u"
,27);
try
{
$req = $db_bbn->query($bbnq); }
catch (
Exception $e)
{
bbnf_pdo_error($e,__FILE__,__LINE__); }
if (
$r = $req->fetch() )
{ echo
"This query has a row result"; }
else
{ echo
"This query has an empty result"; }
?>
-17
Ome Ko
13 年前
不要这样做
if($objStatement->fetch()) return $objStatement->fetch();

你想要
if($blah=$objStatement->fetch()) return $blah;

相信我。
-20
sumariva at gmail dot com
11 年前
我在使用 mssql 的存储过程进行 fetch 时遇到了问题,并遇到了 PDOException

SQLSTATE[IMSSP]: The active result for the query contains no fields

使用类似的准备语句
EXEC [mydb].[stored_procedure_that_returns_select] ?;

解决方案是抑制记录计数
SET NOCOUNT ON; EXEC [mydb].[stored_procedure_that_returns_select] ?;

希望它能帮助你!
To Top