ジェネレータと 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('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);
}
}
?>
しかし、柔軟性を実現するために犠牲にしていることもあります。 ジェネレータは前方にしか進めないイテレータなので、いったん反復処理が始まれば巻き戻すことができません。 これはつまり、同じジェネレータを何度も使い回せないということです。 ジェネレータ関数を呼んでもう一度作り直す必要があります。
+add a note
User Contributed Notes 2 notes
mNOSPAMsenghaa at nospam dot gmail dot com ¶
11 years ago
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.
sergeyzsg at yandex dot ru ¶
10 years ago
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);
}
?>
↑ and ↓ to navigate •
Enter to select •
Esc to close
Press Enter without
selection to search using Google