Главное преимущество генераторов — простота. Требуется написать гораздо меньше шаблонного кода по сравнению с реализацией объекта класса 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);
}
}
?>
Однако за эту гибкость приходится платить: генераторы — однонаправленные итераторы и их нельзя перемотать после начала итерации. Это также означает, что один и тот же генератор нельзя повторять несколько раз: генератор необходимо пересоздавать каждый раз, снова вызвав функцию генератора.