·PDO_FETCH_BOTH - 每个行抓取返回一个既按照列位置又按照列名索引的数组。也就是上述两种情况的直接组合。如果没有指定抓取模式,则该模式为默认模式。
·PDO_FETCH_OBJ - 每个行抓取返回一个匿名对象,其属性名与列名对应。
while ($row = $stmt->fetch(PDO_FETCH_ASSOC)) {
echo "Extension {$row->EXTENSION} by {$row->NAME}<br>";
}
·PDO_FETCH_LAZY - 每个行抓取返回一个引用语句对象的重载对象。这“看起来”好像是 PDO_FETCH_OBJ 和 PDO_FETCH_BOTH 的组合,只是只有当您在脚本中访问 PHP 变量时才创建这些变量。
·PDO_FETCH_BOUND - 抓取每行,返回 TRUE。在使用绑定输出列时这种方式非常有用,它可以避免创建不需要的任何数组或对象。(请参见下面的示例)。
无论您使用哪种抓取策略,当没有其他行可抓取时,fetch() 方法将会返回 FALSE。
现在我要讲述一些技巧,如果您需要最后再调整一下脚本性能的话,这些技巧可能会对您有所帮助。但先给你一个忠告:要像躲避瘟疫一样避免不成熟的优化。您应该总是首选最清晰、可维护性最好的解决方案。请记住,在一个典型的 Web 应用程序中,您不能衡量各种抓取模式间的区别,除非脚本要处理很多行。我再重复一遍:抓取模式间的性能区别非常小 - 请使用最适合您代码的模式。
请记住,使用 PDO_FETCH_NUM 的花销最小,因为访问列数据只是一个简单的数值查询。PDO_FETCH_OBJ 使您能够使用 OO 语法将数据集的列作为对象的属性来访问,但是每个属性访问都涉及一个附加的散列查询,使得使用它的花销基本上与 PDO_FETCH_ASSOC 相同。每个这样的模式都会复制整行,从而占用稍多的内存。
很多数据库驱动程序都会代表您预先抓取并缓存一定数量的行。PHP 每次访问其中一个这样行中的列时,它都需要将其复制到自己的专用内存区域中。如果您的查询涉及很多行,而只需要基于某种复杂的逻辑访问给定行的特定列,则您会发现 PDO_FETCH_LAZY 是一种避免使用很多内存的有用方法,因为它只有在您访问给定列时才复制该列。使用此方式时要注意,从某个给定语句为每个 fetch() 抓取的“惰性对象”是每次迭代时使用的同一对象(以减少每次创建/销毁它的开销)。这就暗示着您不能只是简单地存储该对象用于以后的比较,因为它仍然会引用该语句的当前行 - 您需要手动复制所需要的部分。
最后一种模式为 PDO_FETCH_BOUND,该模式会告知 PDO 您已经将所有列绑定到了 PHP 变量,并且除了要它在到达行集的末尾时通知您外不需要它执行别的任何操作。绑定输出列在概念上与绑定输入参数相似,只是绑定输出列可以用于所有数据库驱动程序。您可以将 PHP 变量绑定到命名列,PDO 将在每次调用 execute() 时对其进行更新。此技术可用来剃去结果集中每列、每行的一些虚拟机器操作码(这种代码速度比原生码要慢)。这种技术的缺点在于,可能会使您的代码难以跟踪(也称为 WTF 系数较高),您使用变量名称时需要倍加小心。下面的代码说明了绑定输出列的使用。请注意,您不必指定 PDO_FETCH_BOUND 即可使用 $stmt->bindColumn();PDO_FETCH_BOUND 只是一个对于您了解只能使用绑定值的情况的一种优化。
$stmt = $dbh->prepare("SELECT extension, name from CREDITS");
if ($stmt->execute()) {
$stmt->bindColumn('EXTENSION', $extension);
$stmt->bindColumn('NAME', $name);
while ($stmt->fetch(PDO_FETCH_BOUND)) {
echo "Extension:$extension, Author:$name\n";
}
}
可移植性
区分大小写的列
PDO 旨在令使用可移植 SQL 的脚本运行良好、可移植。本文中提及的所有查询(调用存储过程除外)在使用任何 PDO 驱动程序时其运行性能应该相同 - 包括所有绑定输入变量和绑定输出列。
但有一个转换问题 - 当您使用 PDO_FETCH_ASSOC 抓取数据时,不同的驱动程序会以不同的方式返回列名 - 某些会将列名转化为大写,某些转换为小写,某些则会使其呈查询中指定的样式。这对于 PHP 脚本来说是一个潜在的问题,因为数组键区分大小写。PDO 提供了一个兼容性属性来帮助规范脚本的结果。下面的小代码段是上面 PDO_FETCH_BOUND 示例的可移植版本,因为 setAttribute() 方法调用会指导 PDO 将抓取返回的列名全部转换为大写:
$dbh = new PDO('OCI:', 'scott', 'tiger');
$dbh->setAttribute(PDO_ATTR_CASE, PDO_CASE_UPPER);
stmt = $dbh->prepare("SELECT extension, name from CREDITS");
if ($stmt->execute()) {
$stmt->bindColumn('EXTENSION', $extension);
$stmt->bindColumn('NAME', $name);
while ($stmt->fetch(PDO_FETCH_BOUND)) {
echo "Extension:$extension, Author:$name\n";
}
}
除了 PDO_CASE_UPPER 之外,还有 PDO_CASE_LOWER(它会将列名转换为小写)和 PDO_CASE_NATURAL(它是默认选项:使列保持数据库驱动程序返回的形式)。
错误和错误处理