2024 日本 PHP 研討會

比較產生器與 迭代器 物件

產生器的主要優點是它們的簡潔性。與實作 迭代器 類別相比,需要編寫的樣板程式碼要少得多,而且程式碼通常更易讀。例如,以下函式和類別是等效的

<?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 筆筆記

107
mNOSPAMsenghaa at nospam dot gmail dot com
11 年前
就規模而言,這兩個例子之間的比較似乎不太公平。如前所述,產生器是僅向前迭代的,這意味著它應該與定義了虛擬 rewind 函式的迭代器進行比較。此外,為了公平起見,由於迭代器會拋出異常,產生器範例是否也應該拋出相同的異常?程式碼比較應該更像這樣

<?php
function getLinesFromFile($fileName) {
if (!
$fileHandle = fopen($fileName, 'r')) {
throw new
RuntimeException('無法開啟檔案 "' . $fileName . '"');
}

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() { }

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);
}
}
?>

產生器顯然還是簡短得多,但这似乎是一個更合理的比較。
23
sergeyzsg at yandex dot ru
10 年前
我認為這是一個不好的生成器範例。
如果使用者沒有讀取所有行,檔案將不會被關閉。

<?php
function getLinesFromFile($fileHandle) {
while (
false !== $line = fgets($fileHandle)) {
yield
$line;
}
}

if (
$fileHandle = fopen($fileName, 'r')) {
/*
使用 getLinesFromFile 執行一些操作
*/
fclose($fileHandle);
}
?>
To Top