douqiao5552 2011-11-08 09:16
浏览 48
已采纳

使用PHP迭代器

friends. I know, there are many questions here already on these iterators. I've read something, and I'm not a beginner... but my mind is somewhat stuck on this. Please, help me to comprehend how I use iterators in practice.

Suppose, I have an ORM object that can select instances from database. And one instance contains fields and can insert, uodate etc. As usual. I want to iterate through all objects of a type, but as there can be plenty of them, I prefer to select them by "pages". My code:

$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);

I feel that iterator paradigm is what suits here, but what interface is better to implement in this case or maybe some base SPL class?

UPDATE Ideally code above with iterator may look like:

$iterator = new ORMPagedIterator($ormobject, $filter, $sorting);
foreach ($iterator as $rec)
{
  // do something with record
}

E.g. all that page by page behavior is inside the iterator.

  • 写回答

1条回答 默认 最新

  • douwei8295 2011-11-08 12:45
    关注

    I would use an Iterator that iterates over another Iterator and asks for a next Iterator once it reaches the end of the previous Iterator... ok, sounds a mo complicated than it actually is:

    <?php
    $limit = 100;
    $offset = 0;
    
    $iter = new NextIteratorCallbackIterator(function($i) use ($orm, $limit, &$offset) {
        printf("selecting next bunch at offset %d
    ", $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
    }
    ?>
    

    And here is a sample Implementation of that 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;
        }
    }
    ?>
    

    UPDATE: Your ORMPagedIterator can be implemented using NextIteratorCallbackIterator as easy as:

    <?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"));
        }
    }
    ?>
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 改算法,照着压缩包里边,参考其他代码封装的格式 写到main函数里
  • ¥15 用windows做服务的同志有吗
  • ¥60 求一个简单的网页(标签-安全|关键词-上传)
  • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 一直显示正在等待HID—ISP