This hardly seems a fair comparison between the two examples, size-for-size. As noted, generators are forward-only, meaning that it should be compared to an iterator with a dummy rewind function defined. Also, to be fair, since the iterator throws an exception, shouldn't the generator example also throw the same exception? The code comparison would become more like this:
<?php
function getLinesFromFile($fileName) {
if (!$fileHandle = fopen($fileName, 'r')) {
throw new RuntimeException('Couldn\'t open file "' . $fileName . '"');
}
while (false !== $line = fgets($fileHandle)) {
yield $line;
}
fclose($fileHandle);
}
// versus...
class LineIterator implements Iterator {
protected $fileHandle;
protected $line;
protected $i;
public function __construct($fileName) {
if (!$this->fileHandle = fopen($fileName, 'r')) {
throw new RuntimeException('Couldn\'t open file "' . $fileName . '"');
}
}
public function rewind() { }
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);
}
}
?>
The generator is still obviously much shorter, but this seems a more reasonable comparison.Споредба на генератори со Iterator објекти
Почист и полокален преглед на PHP референцата, со задржана структура од PHP.net и подобра читливост за примери, секции и белешки.
Споредба на генератори со Iterator објекти
Референца за `language.generators.comparison.php` со подобрена типографија и навигација.
Споредба на генераторите со Итератор objects
Главната предност на генераторите е нивната едноставност. Многу помалку код за обем треба да се напише во споредба со имплементирање на Итератор класа, а кодот е генерално многу почитлив. На пример, следната функција и класа се еквивалентни:
<?php
function getLinesFromFile($fileName) {
if (!$fileHandle = fopen($fileName, 'r')) {
return;
}
while (false !== $line = fgets($fileHandle)) {
yield $line;
}
fclose($fileHandle);
}
// versus...
class LineIterator implements Iterator {
protected $fileHandle;
protected $line;
protected $i;
public function __construct($fileName) {
if (!$this->fileHandle = fopen($fileName, 'r')) {
throw new RuntimeException('Couldn\'t open file "' . $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);
}
}
?>Оваа флексибилност доаѓа со цена, меѓутоа: генераторите се итератори само напред, и не можат да се вратат назад откако ќе започне итерацијата. Ова исто така значи дека истиот генератор не може да се итерира повеќе пати: генераторот ќе треба да се изгради повторно со повикување на функцијата генератор повторно.
Белешки од корисници 2 забелешки
I think that this is bad generator example.
If user will not consume all lines then file will not be closed.
<?php
function getLinesFromFile($fileHandle) {
while (false !== $line = fgets($fileHandle)) {
yield $line;
}
}
if ($fileHandle = fopen($fileName, 'r')) {
/*
something with getLinesFromFile
*/
fclose($fileHandle);
}
?>