PHP mysqli_结果:使用带有fetch_对象的可遍历接口
PHP mysqli_result类实现可遍历接口已有一段时间了。 这提供了一些有趣的可能性,如以下代码: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
$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
}