PHPのジェネレータ

lab.adn-mobasia.net

アッ (活用するの忘れてた感)


これを! (↓↓Iteratorインタフェースの実装例↓↓)

<?php
// ファイルの行データの読み込みクラス
class FileLineIterator implements Iterator {
    private $fp = null;
    private $line = null;
 
    public function __construct($filepath) {
        $this->fp = fopen($filepath, "rb");
    }
    public function __destruct() {
        @fclose($this->fp);
    }
    public function current() {
        return $this->line;
    }
    public function key() {
        throw new BadFunctionCallException();
    }
    public function next() {
        $this->line = fgets($this->fp);
        return $this->line;
    }
    public function rewind() {
        return rewind($this->fp);
    }
    public function valid() {
        return (!is_null($this->fp) && $this->line !== false);
    }
}
 
// 処理の開始
$num = 1;
$iterator = new FileLineIterator($argv[1]);
foreach($iterator as $line) {
    // ここで行番号を出力する
    printf("%5d: %s", $num++, $line);
}


こうや!(↓↓yield()↓↓↓)

<?php
// ファイルの行データの読み込み関数
function file_get_lines($filepath) {
    $lines = array();
    $fp = fopen($filepath, "rb");
    while(($line = fgets($fp)) !== false) {
        // yieldキーワードで$lineを都度返却することができる
        yield $line;
    }
    fclose($fp);
}
 
// 処理の開始
$num = 1;
foreach(file_get_lines($argv[1]) as $line) {
    // ここで行番号を出力する
    printf("%5d: %s", $num++, $line);
}


ということです。


でっかい配列変数に展開するとメモリを喰い、Iteratorをimplementすると大げさで遅いし、という事で。
途中結果をreturnして値の供給を続けるやつ。

yield ... 産出する,(利益が)出る, (相手に)屈服する



次のようにも書けるので、foreach()を使った既存の記述も置き換えやすいですね。そうですね。

<?php
// ファイルの行データの読み込み関数
function file_get_lines($filepath) {
    $lines = array();
    $fp = fopen($filepath, "rb");
    while(($line = fgets($fp)) !== false) {
        // yieldキーワードで$lineを都度返却することができる
        yield $line;
    }
    fclose($fp);
}

$f = file_get_lines($argv[1]);

// 処理の開始
$num = 1;
foreach($f as $line) {
    // ここで行番号を出力する
    printf("%5d: %s", $num++, $line);
}