Сравнение генераторов с объектами класса Iterator

Главное преимущество генераторов — простота. Требуется написать гораздо меньше шаблонного кода по сравнению с реализацией объекта класса Iterator, и этот код гораздо более простой и понятный. Например, эта функция и класс делают одно и то же.

<?php

function getLinesFromFile($fileName)
{
    if (!$fileHandle = fopen($fileName, 'r')) {
        return;
    }

    while (false !== $line = fgets($fileHandle)) {
        yield $line;
    }

    fclose($fileHandle);
}

// Против...

class LineIterator implements Iterator
{
    protected $fileHandle;

    protected $line;
    protected $i;

    public function __construct($fileName)
    {
        if (!$this->fileHandle = fopen($fileName, 'r')) {
            throw new RuntimeException('Невозможно открыть файл "' . $fileName . '"');
        }
    }

    public function rewind()
    {
        fseek($this->fileHandle, 0);
        $this->line = fgets($this->fileHandle);
        $this->i = 0;
    }

    public function valid()
    {
        return false !== $this->line;
    }

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

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

    public function next()
    {
        if (false !== $this->line) {
            $this->line = fgets($this->fileHandle);
            $this->i++;
        }
    }

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

Однако за эту гибкость приходится платить: генераторы — однонаправленные итераторы и их нельзя перемотать после начала итерации. Это также означает, что один и тот же генератор нельзя повторять несколько раз: генератор необходимо пересоздавать каждый раз, снова вызвав функцию генератора.

Смотрите также