friend 。我知道,这里已经有很多关于这些迭代器的问题。 我读过一些东西,我不是初学者......但我的想法有点停留在这个上面。请帮助我理解如何在实践中使用迭代器。
假设,我有一个可以从数据库中选择实例的 ORM 对象。一个实例包含字段,可以像往常一样插入、更新等。 我想遍历一个类型的所有对象,但由于它们可能很多,所以我更喜欢按“页面”选择它们。我的代码:
$limit = 100;
$offset = 0;
do
{
$recs = $orm->select($filter, $sorting, $limit , $offset);
$offset += $limit;
foreach ($recs as $rec)
{
// doing something with record
}
}
while (count($recs) == $limit);
我觉得迭代器范式适合这里,但在这种情况下哪种接口(interface)更适合实现,或者某些基础 SPL 类?
更新 理想情况下,上面带有迭代器的代码可能如下所示:
$iterator = new ORMPagedIterator($ormobject, $filter, $sorting);
foreach ($iterator as $rec)
{
// do something with record
}
例如所有逐页行为都在迭代器中。
最佳答案
我会使用一个迭代器来迭代另一个迭代器,并在它到达前一个迭代器的末尾时请求下一个迭代器……好吧,听起来比实际情况要复杂:
<?php
$limit = 100;
$offset = 0;
$iter = new NextIteratorCallbackIterator(function($i) use ($orm, $limit, &$offset) {
printf("selecting next bunch at offset %d\n", $offset);
$recs = $orm->select($filter, $sorting, $limit , $offset);
$offset += $limit;
if ($recs) {
return new ArrayIterator($recs);
}
return null; // end reached
});
foreach ($iter as $rec) {
// do something with record
}
?>
下面是 NextIteratorCallbackIterator 的示例实现:
<?php
class NextIteratorCallbackIterator implements Iterator {
private $_iterator = null;
private $_count = 0;
private $_callback;
public function __construct($callback) {
if (!is_callable($callback)) {
throw new Exception(__CLASS__.": callback must be callable");
}
$this->_callback = $callback;
}
public function current() {
return $this->_iterator !== null ? $this->_iterator->current() : null;
}
public function key() {
return $this->_iterator !== null ? $this->_iterator->key() : null;
}
public function next() {
$tryNext = ($this->_iterator === null);
do {
if ($tryNext) {
$tryNext = false;
$this->_iterator = call_user_func($this->_callback, ++$this->_count);
}
elseif ($this->_iterator !== null) {
$this->_iterator->next();
if ($this->_iterator->valid() == false) {
$tryNext = true;
}
}
} while ($tryNext);
}
public function rewind() {
$this->_iterator = call_user_func($this->_callback, $this->_count = 0);
}
public function valid () {
return $this->_iterator !== null;
}
}
?>
更新:您的 ORMPagedIterator 可以使用 NextIteratorCallbackIterator 轻松实现:
<?php
class ORMPagedIterator implements IteratorAggregate {
function __construct($orm, $filter, $sorting, $chunksize = 100) {
$this->orm = $orm;
$this->filter = $filter;
$this->sorting = $sorting;
$this->chunksize = $chunksize;
}
function iteratorNext($i) {
$offset = $this->chunksize * $i;
$recs = $this->orm->select($this->filter, $this->sorting, $this->chunksize, $offset);
if ($recs) {
return new ArrayIterator($recs);
}
return null; // end reached
}
function getIterator() {
return new NextIteratorCallbackIterator(array($this,"iteratorNext"));
}
}
?>
关于php - 使用 PHP 迭代器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8048156/