PHP Generators 產生器

Generator 是一個簡單版Iterator,不同的是不需要實作 Iterator。 只有在需要的時候計算並產生迭代的數值,減少佔用記憶體空間。

Generators

<?php
function myGenerator()
{
    yield 'value1';
    yield 'value2';
    yield 'value3';
}

foreach (myGenerator() as $yieldValue) {
    echo $yieldValue , PHP_EOL;
}

/**
 * Result:
 *   value1
 *   value2
 *   value2
 */

Generator 不是解決 Iterator 的萬靈藥, 不會知道下一個迭代值,只能用它進行往前的迭代, 用過即丟,無法利用同一個 Generator 重複迭代。

方法比較

方法1: 如果都沒有使用 Iterator, Generator

<?php
function getLines($fileName)
{
    $lines = [];
    $file = fopen($fileName, 'r');
    while (!feof($file)) {
        $lines[] = fgets($file);
    }
    fclose($file);
    return $lines;
}

foreach (getLines('myFile') as $line) {
    echo $line , PHP_EOL;
}

檔案小還好,如果檔案大到GB,記憶體可能就會不足

方法2: 用 Iterator

<?php
class FileIterator implements Iterator
{
    protected $file;
    protected $key = 0;
    protected $current;

    public function __construct($file)
    {
        $this->file = fopen($file, 'r');
    }

    public function __destruct()
    {
        fclose($this->file);
    }

    public function current()
    {
        return $this->current;
    }

    public function key()
    {
        return $this->key;
    }

    public function next()
    {
        $this->current = fgets($this->file);
    }

    public function rewind()
    {
        rewind($this->file);
        $this->current = fgets($this->file);
        $this->key = 0;
    }

    public function valid()
    {
        return !feof($this->file);
    }

}

$file = new FileIterator('myFile');
foreach ($file as $line) {
    echo $line , PHP_EOL;
}

要實作必須寫一堆 method ,符合 Iterator 介面

方法3: 用 Generator

<?php

function getLines($fileName)
{
    $file = fopen($fileName, 'r');
    while (!feof($file)) {
        yield fgets($file);
    }
}

foreach (getLines('myFile') as $line) {
    echo $line , PHP_EOL;
}

簡潔很多,但無法知道下一個迭代值,只能向前迭代

參考資料