使用 foreach 获取时覆盖 PDO 的 fetch()

Posted

技术标签:

【中文标题】使用 foreach 获取时覆盖 PDO 的 fetch()【英文标题】:Overriding fetch() for PDO when fetching using foreach 【发布时间】:2011-03-20 23:23:47 【问题描述】:

我扩展了PDOStatement 并修改了fetch() 方法以将PostgreSQL 中时间戳和数组类型的值类型转换为日期时间和本机数组。这可以按预期工作,但在 foreach 中使用该语句时我无法覆盖该行为。

我通过将行返回到实现 ArrayAccess、IteratorAggregate 和 Countable 的对象中解决了这个问题。但是我对那个解决方案并不满意,只想要一个纯数组。

例子:

类 ExtendedStatement 扩展 PDOStatement 受保护的函数 __construct() $this->setFetchMode(PDO::FETCH_ASSOC); 公共函数获取( $fetch_style = PDO::FETCH_ASSOC, $cursor_orientation = PDO::FETCH_ORI_NEXT, $cursor_offset = 0) $r = parent::fetch($fetch_style, $cursor_orientation, $cursor_offset); if (is_array($r)) $r["额外数据"] = TRUE; 返回 $r; $db = new PDO("sqlite::memory:"); $db->setAttribute( PDO::ATTR_STATEMENT_CLASS, array("ExtendedStatement", array($db))); $db->e​​xec("创建表示例(id INTEGER PRIMARY KEY, name VARCHAR)"); $db->e​​xec("INSERT INTO example(name) VALUES('test')"); // 这就是它的作用 $s = $db->prepare("SELECT * FROM example"); $s->执行(); foreach ($s as $r) var_dump($r); $s->closeCursor(); // 这就是我想要的样子 $s = $db->prepare("SELECT * FROM example"); $s->执行(); 而 ($r = $s->fetch()) var_dump($r); $s->closeCursor(); // 这就是我想要的样子 $s = $db->prepare("SELECT * FROM example"); $s->执行(); var_dump($s->fetch()); $s->closeCursor();

输出:

数组(2) [“身份证”]=> 字符串(1)“1” [“名称”]=> 字符串(4)“测试” 数组(3) [“身份证”]=> 字符串(1)“1” [“名称”]=> 字符串(4)“测试” [“额外数据”]=> 布尔(真) 数组(3) [“身份证”]=> 字符串(1)“1” [“名称”]=> 字符串(4)“测试” [“额外数据”]=> 布尔(真)

【问题讨论】:

你能展示一些按预期工作但没有按预期工作的代码吗?如果您已覆盖 fetch,它应该始终“正确”工作。 更新了一个例子。 while($r = $s->fetch()) 替换foreach是否正常?另外,请记住,parent::fetch 调用返回的结果很可能不是数组,它可能为空。您可能应该添加一个is_array 检查或类似的东西。 是的,它按预期工作。我的正常代码有效,但这开始循环到无穷大。此代码只是演示行为的示例。这不是真正的代码。 【参考方案1】:

PDOStatement 类实现了内置的仅限内部的 Traversable 接口。它实现的迭代器绕过了公共的PDOStatement::fetch() 方法。

【讨论】:

我已经意识到了这一点,但我仍然想以某种方式破解它。我有一个实现迭代器的想法,但为了更好的解决方案而放弃了它。 @antennen:嗯,你真的有三个选择:1)补丁ext/pdo/pdo_stmt.c,2)改用while,3)实现你自己的迭代器。无论如何,我可能会建议您在bugs.php.net 提交错误。它应该调用公共的fetch() 方法似乎很合理。 错误报告:bugs.php.net/bug.php?id=52444。我现在可能会尝试自己的迭代器方法。【参考方案2】:

我使用这样的东西:

$db->setAttribute(PDO::mysql_ATTR_USE_BUFFERED_QUERY, false);
$sql = 'select * from table';
$stmt = $db->prepare($sql);
$stmt->execute();

while($row = $stmt->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT))

    // do stuff

所以你唯一需要做的就是设置一些选项:)

【讨论】:

鉴于他的问题示例中已经有这种代码,我很确定他知道这种可能性。

以上是关于使用 foreach 获取时覆盖 PDO 的 fetch()的主要内容,如果未能解决你的问题,请参考以下文章

php pdo foreach

PDO - foreach 只更新最后一个

PDO - 对多个 foreach 循环使用相同的查询

PDO 使用 foreach 绑定 n 次相同的值

为托管程序中的 foreach php pdo 提供的参数无效

PDO::bindParam 在 foreach 循环中,所有值都设置为相同吗?