PHP的迭代器和生成器

一.迭代器

分析:想一下,如果把集合对象和对集合对象的操作放在一起,当我们想换一种方式遍历集合对象中元素时,就需要修改集合对象了,违背“单一职责原则”,而迭代器模式将数据结构和数据结构的算法分离开,两者可独立发展。

优点:

  1. 支持多种遍历方式。比如有序列表,我们根据需要提供正序遍历、倒序遍历两种迭代器。用户只需要得到我们的迭代器,就可以对集合执行遍历操作
  2. 简化了聚合类。由于引入了迭代器,原有的集合对象不需要自行遍历集合元素了
  3. 增加新的聚合类和迭代器类很方便,两个维度上可各自独立变化
  4. 为不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合结构上操作

缺点:

  1. 迭代器模式将存储数据和遍历数据的职责分离增加新的集合对象时需要增加对应的迭代器类,类的个数成对增加,在一定程度上增加系统复杂

具体接口:

Iterator extends Traversable {
   /* 方法 */
   abstract public mixed current ( void )
   abstract public scalar key ( void )
   abstract public void next ( void )
   abstract public void rewind ( void )
   abstract public bool valid ( void )
}

简单的foreach迭代器实现

<?php
    class myIterator implements Iterator {
        private $position = 0;
        private $array = array(
            "firstelement",
            "secondelement",
            "lastelement",
        );  
    
        public function __construct() {
            $this->position = 0;
        }
    
        function rewind() {
            var_dump(__METHOD__);
            $this->position = 0;
        }
    
        function current() {
            var_dump(__METHOD__);
            return $this->array[$this->position];
        }
    
        function key() {
            var_dump(__METHOD__);
            return $this->position;
        }
    
        function next() {
            var_dump(__METHOD__);
            ++$this->position;
        }
    
        function valid() {
            var_dump(__METHOD__);
            return isset($this->array[$this->position]);
        }
    }
    
    $it = new myIterator;
    
    foreach($it as $key => $value) {
        var_dump($key, $value);
        echo "\n";
    }
?>

二.生成器

PHP生成器(generator)是PHP5.5.0引入的功能,与标准的PHP迭代器不同,PHP生成器不要求类实现Iterator接口,从而减轻了类的负担,生成器会根据需求计算并产出要迭代的值,这对性能有重大的影响试想一下假如标准的PHP迭代器经常在内存中执行迭代操作者要预先计算出数据集性能低下;如果要使用特定的的方式对计算大量数据,对性能的影响更甚。此时我们可以使用生成器,即时计算产出后续值不占用宝贵的内存资源。
优点:

  1. 占用内存少对,性能好。每次产出一个值之后,生成器的内部状态都会停顿;当生成器请求下一个值时,内部状态又会恢复。生成器的内部一直在停顿和恢复之间切换,直到循环完成或停顿位置

缺点:

  1. PHP生成器不能满足所有迭代器的需求,因为如果不查询,生成器永远不知道下一个要迭代的值是什么,在生成器中无法后退或前进。
  2. 生成器还是一次性的,无法多次迭代同一个生成器,不过,如果需要,可以重建或克隆生成器。

 
创建生成器:

  1. 因为生成器就是PHP函数,生成器就是在函数中使用yield关键字。与普通的PHP函数不同的是,生产器从不返回值,只产出值。
<?php
        function myGenerator(){    
               yield 'a';    
               yield 'b';    
               yield 'c';
        }
  1. 调用生成器函数时,PHP会返回一个属于Generator类的对象。
    这个对象可以使用foreach()函数迭代。每次迭代,PHP会要求Generator实例计算并提供下一个要迭代的值
<?php
        function makeRange($length){    
               for($i = 0; $i<$length; $i++){        
                      yield $i;       
               }
        } 
        foreach(makeRange(1000000) as $i){    
               echo $i,PHP_EOL;
        }

如上所示:
当$length 很大时(上百万),而且你同时没有使用生成器的话,那么就要预先为一个由一百万上一千五个整数组成的数组分配内存。而PHP生成器能实现相同的操作,不过一次只会为一个整数分配内存

相关推荐