PHP mysqli_结果:使用带有fetch_对象的可遍历接口

PHP mysqli_结果:使用带有fetch_对象的可遍历接口,php,mysqli,Php,Mysqli,PHP mysqli_result类实现可遍历接口已有一段时间了。 这提供了一些有趣的可能性,如以下代码: <?php $db = new mysqli( '...' ); $result = $db->query( '...' ); foreach( $result as $row ) { //$row is an associative array containing the fetched values } 注意: 这是一个内部引擎接口,无法在PHP脚本中实现。

PHP mysqli_result类实现可遍历接口已有一段时间了。 这提供了一些有趣的可能性,如以下代码:

<?php

$db = new mysqli( '...' );

$result = $db->query( '...' );

foreach( $result as $row ) {
   //$row is an associative array containing the fetched values
}
注意:
这是一个内部引擎接口,无法在PHP脚本中实现。必须改用迭代器Aggregate或迭代器。实现扩展可遍历的接口时,请确保在implements子句中列出或在其名称之前


i、 e.您可以在和/或

中找到接口定义,正如我在评论中所述,使用PDO很容易做到您想要的。只需设置
PDO::ATTR_DEFAULT_FETCH_MODE
属性,当您执行foreach循环时,它将执行适当类型的FETCH

您还可以设置
PDO::ATTR_STATEMENT_CLASS
属性来定义要使用的类

$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_CLASS);
$pdo->setAttribute(PDO::ATTR_STATEMENT_CLASS,array('classname',$constructorArgs));
有关更多信息,请参阅

使用该解决方案,您需要根据要实例化的类更改每个查询的
ATTR\u STATEMENT\u CLASS
属性

或者,您可以将其设置为在查询中指定类名:

$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE);
$stmt = $db->query("SELECT 'classname', * FROM `table` WHERE `id` = 1;");
只需将相关类名作为第一个要选择的字段添加到查询中

有关此问题的更多信息,请参阅此相关问题的其中一个答案。

mysqli_结果的(我们称之为)遍历获取模式不会受到影响。因此,默认情况下,关联数组(列名作为键,其值作为值)像
mysqli\u result::fetch\u assoc()
一样保持不变

因此,这需要一个自己的
迭代器来完成这项工作。那么Mysqli结果的非foreach迭代传统上看起来是什么样子呢?右侧的
while()
循环:

while($row = $result->fetch_assoc())
{
   ...
}
其中的内容是:当fetch方法不返回
NULL
时,继续。这是创建迭代的常见形式

对于这类迭代,我通常使用
FetchingIterator
,它是一个具体的迭代器,可以将特定于PHP的
迭代器
接口(倒带、有效、当前、键、下一个)转换为更简化的接口。简化后的方法是:next on rewind,next on next,有效期至
NULL
——这与
while
循环几乎相同,可以用于类似的工作API,如不推荐使用的mysql,甚至是数组(比较等)。它也类似于其他不同编程语言中的迭代器实现,这里特别是Java(比较)

我确实在去年的文章中对其进行了初步概述,并且可以找到一个改进了很多的标准实现,因为它可以轻松地实现您想要做的事情

让我们看一个示例应用程序:

class ObjectFetchIterator extends FetchingIterator
{
    public function __construct(mysqli_result $result, $class) {

        parent::__construct(function() use ($result, $class) {
            return $result->fetch_object($class);
        });
    }
}
mysqli\u result::fetch\u object()
方法以前在
中,而(…)
现在已移动到mysqli结果的
FetchingIterator
的构造函数中。这是一个非常直接的实现。或者,也可以重写受保护的
fetchNext()
方法,但我之所以注意它,是因为这里不需要它

使用示例非常简单:

$db       = new mysqli('...');    
$result   = $db->query('...');    
$iterator = new ObjectFetchIterator($result, 'myClass');

/* @var $row myClass */
foreach ($iterator as $row)
{
   // $row is a myClass now based on fetched values
}
如本例所示,没有必要为此使用PDO,这听起来像是一个相当懒惰的借口:只为这个小细节更改整个数据库层?不情况正好相反:在
foreach
中使用迭代器可以将代码从具体的数据库访问库分离到泛型类型(正如前面的数组一样,但是数组与对象类型没有那么明显)


希望这有帮助,即使答案来得有点晚。我刚刚注意到,到目前为止,这还没有得到真正的回答。

因此我需要定义一个扩展的ArrayIterator类,该类将获取的数组转换为offsetGet中所需的对象,然后在mysqli_result_扩展中实现IteratorAggregate,该扩展在getIterator()中返回$this的新*迭代器实例?使用迭代器,我必须为它定义所有的方法,我真的不想写20个方法和额外的类,只是为了把fetch_assoc变成fetch_object,有没有其他方法?你可以切换到PDO吗?不知道如何在MySQLi中实现这一点,但使用PDO可以轻松实现您想要的功能。只需设置
PDO::ATTR\u DEFAULT\u FETCH\u MODE
属性,当您执行foreach循环时,它将执行适当类型的FETCH。如果我还能够指定result对象的类,这将是一个很好的解决方案。我翻遍了PDO的文档,但找不到方法。Afaik扩展PDOStatement类会导致与扩展mysqli_result相同的问题,因为它还实现了Traversableyes,您可以。我将把它作为一个带有代码的答案发布。非常感谢,这肯定会帮助我完成这项工作!我可能会使用PDO::FETCH_类类型样式,它似乎是最“动态”的方式
class ObjectFetchIterator extends FetchingIterator
{
    public function __construct(mysqli_result $result, $class) {

        parent::__construct(function() use ($result, $class) {
            return $result->fetch_object($class);
        });
    }
}
$db       = new mysqli('...');    
$result   = $db->query('...');    
$iterator = new ObjectFetchIterator($result, 'myClass');

/* @var $row myClass */
foreach ($iterator as $row)
{
   // $row is a myClass now based on fetched values
}