2024年PHP开发者大会 日本

比较生成器与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);
}
}
?>

然而,这种灵活性是有代价的:生成器是单向迭代器,一旦迭代开始就无法回退。这也意味着同一个生成器无法多次迭代:需要再次调用生成器函数来重建生成器。

另见

添加注释

用户贡献注释 2 条注释

mNOSPAMsenghaa at nospam dot gmail dot com
11 年前
这两个示例的比较似乎并不公平,大小相同。如前所述,生成器是单向的,这意味着它应该与定义了虚拟回退函数的迭代器进行比较。此外,为了公平起见,由于迭代器抛出异常,生成器示例是否也应该抛出相同的异常?代码比较将变得更像这样

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

// 与...相比

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

生成器仍然明显短得多,但这似乎是一个更合理的比较。
[email protected]
10年前
我认为这是一个不好的生成器示例。
如果用户不读取所有行,则文件不会关闭。

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

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