PHP的迭代器和生成器

碼魘發表於2019-02-16

一.迭代器

分析:想一下,如果把集合物件和對集合物件的操作放在一起,當我們想換一種方式遍歷集合物件中元素時,就需要修改集合物件了,違背“單一職責原則”,而迭代器模式將資料結構和資料結構的演算法分離開,兩者可獨立發展。

優點:

  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 "
";
    }
?>

二.生成器

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生成器能實現相同的操作,不過一次只會為一個整數分配記憶體

相關文章