警告
在处理空数据集时,fetch() 不会遵循 SQL-92 SQLSTATE 标准。
它不会将错误代码类设置为 20 以指示“未找到数据”,而是返回类 00 表示成功,并将 NULL 返回给调用方。
这也阻止了异常机制的触发。
程序员需要在任何 fetch*() 之后显式地为空结果集编写测试,而不是依赖于 RDBMS 的默认行为。
我尝试将其记录为错误,但它被驳回为“按预期工作”。只是提醒一下。
(PHP 5 >= 5.1.0, PHP 7, PHP 8, PECL pdo >= 0.1.0)
PDOStatement::fetch — 获取结果集中的下一行
$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_BOTH
和 PDO::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.
警告
在处理空数据集时,fetch() 不会遵循 SQL-92 SQLSTATE 标准。
它不会将错误代码类设置为 20 以指示“未找到数据”,而是返回类 00 表示成功,并将 NULL 返回给调用方。
这也阻止了异常机制的触发。
程序员需要在任何 fetch*() 之后显式地为空结果集编写测试,而不是依赖于 RDBMS 的默认行为。
我尝试将其记录为错误,但它被驳回为“按预期工作”。只是提醒一下。
有人已经指出 SQLite 驱动程序不支持 PDO::CURSOR_SCROLL。还值得注意的是,MySQL 驱动程序也不支持它。
事实上,如果您尝试对 MySQL 语句使用可滚动游标,则 PDO::FETCH_ORI_ABS 参数和传递给 fetch() 的偏移量将被静默忽略。fetch() 将按正常方式运行,按照从数据库中获取到的顺序返回行。
一开始这实际上是一个非常令人困惑的行为。即使只是作为此页面上的用户添加的注释,也绝对值得记录。
在 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。
获取返回的第一条条目的快速单行代码。这对于非常基本的查询很有用。
<?php
$count = current($db->query("select count(*) from table")->fetch());
?>php
获取对象时,默认情况下会在填充字段后调用类的构造函数。
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
这是使用 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!
我不仅认为这是一个糟糕的设计选择,而且很遗憾的是,手册中没有任何地方记录了这一点——事实上,手册没有明确说明哪些驱动程序支持哪些属性,哪些不支持,因此开发人员只能玩猜谜游戏。
希望这能为一些开发人员节省一些麻烦。
祝你好运,
一位之前的发帖者指出,当没有结果时,此函数返回 NULL。这是错误的。此函数返回一个空数组。fetchAll() 返回相同的内容。
此外,文档指定了“失败”时会发生什么,但没有说明什么构成“失败”。“失败”可能是函数没有返回结果的情况;也就是说,查询“失败”了。但是,“失败”显然是指 PDO 错误函数会显示“失败”的情况,例如非法的 SQL 语法或对不存在的表的查询等。空结果不是“失败”。也许这对其他人来说很明显,但对我来说并非如此。
如果您要为记录使用类的新的实例,您可以使用
<?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);
?>
由于 MySQL 目前不支持使用游标,因此在使用 PDO 访问 MySQL 数据库时,$cursor_offset 功能无法工作。
如果您尝试任意访问 MySQL 数据库记录集中特定记录或记录组,可以考虑使用 SELECT 语句的 LIMIT 子句来实现此目的,例如 LIMIT 5,3 返回第 6、7 和第 8 条记录 - 从索引 5(即第 6 条记录)开始的 3 条记录。
如果您想使用 PDO::FETCH_CLASS,则需要先使用 setFetchMode 进行设置,如下所示
$stmt->setFetchMode( PDO::FETCH_CLASS, 'classType', array( 'parameters to constructor' );
$object = $stmt->fetch( PDO::FETCH_CLASS );
如果您省略此操作,PHP 将出现段错误。
这只是一个关于第二个参数 -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 :-
通过结果集中游标的当前位置的相对位置获取请求的行。仅对可滚动游标有效。
在使用预处理语句和 MySQL 时,请注意 fetch()(我不知道其他数据库的情况)。Fetch 不会关闭游标,也不会允许您发送任何其他查询,即使您的结果集只有一行。
如果您使用 $statement->fetch(),则之后还必须使用 $statement->closeCursor(),才能执行另一个查询。
或者,您可以使用 $statement->fetchAll() 而无需 $statement->closeCursor()。
似乎如果您使用 $statement->query() 执行 INSERT 语句,然后执行 $statement->fetch(),您将收到一个异常,提示:SQLSTATE[HY000]: General error。
我花了几个小时试图找出如何使用 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;
?>
请注意,通过这种方式,“提取模式”将被“覆盖”,并且不会应用 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();
?>
我可以使用 PDO::FETCH_COLUMN 检索结果的第一列。
$ps->fetch( PDO::FETCH_COLUMN );
在使用 PHP 5.3.10 的 Postgresql 上运行。
请注意,PDO::ATTR_STRINGIFY_FETCHES 对于 MySQL 驱动程序不起作用。MySQL 将始终返回字符串,因为这是核心 mysql PHP 扩展的行为。请参阅 http://bugs.php.net/bug.php?id=44341
使用 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"
}