使用 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->exec("创建表示例(id INTEGER PRIMARY KEY, name VARCHAR)"); $db->exec("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()的主要内容,如果未能解决你的问题,请参考以下文章