# 生成器与 Iterator 对象比较

生成器的主要优点是简单。与实现 `Iterator` 类相比，编写更少的代码 ，并且代码通常更具可读性。然而，这种灵活性需要付出代价，生成器只是仅向前迭代器，一旦迭代开始就无法倒回。这也意味着同一个生成器不能多次迭代，生成器需要通过再次调用生成器函数来重建，或者通过 `clone` 关键字克隆。

```php
<?php

/**
 * Yielding test values.
 *
 * @param  void
 * @return void
 */
function foo()
{
    $handle = fopen(__DIR__ . '/example.txt', 'r');
    while ($line = fgets($handle)) {
        yield trim($line);
    }
}

class Foo implements Iterator
{
    /**
     * Store a handle.
     *
     * @var resource
     */
    private $property;

    /**
     * Store the current line content.
     *
     * @var string|bool
     */
    private $line;

    /**
     * Store the current line number.
     *
     * @var int
     */
    private int $number;

    /**
     * Store a handle to the property.
     *
     * @param  void
     * @return void
     */
    public function __construct()
    {
        $this->property = fopen(__DIR__ . '/example.txt', 'r');
    }

    /**
     * Return the current line content of the specified property.
     *
     * @param  void
     * @return string
     */
    public function current(): string
    {
        return trim($this->line);
    }

    /**
     * Save the next line content and line number to the specified property and advance the file pointer.
     *
     * @param  void
     * @return void
     */
    public function next()
    {
        if ($this->line !== false) {
            $this->line = fgets($this->property);
            $this->number++;
        }
    }

    /**
     * Return the current line number of the specified property.
     *
     * @param  void
     * @return int
     */
    public function key(): int
    {
        return $this->number;
    }

    /**
     * Return the validity of the current position of the specified property.
     *
     * @param  void
     * @return bool
     */
    public function valid(): bool
    {
        return $this->line !== false;
    }

    /**
     * Set the file pointer of the specified property to the first line and rewind the value of the specified property.
     *
     * @param  void
     * @return void
     */
    public function rewind()
    {
        fseek($this->property, 0);
        $this->line = fgets($this->property);
        $this->number = 0;
    }
}

$foo = foo();
foreach ($foo as $value) {
    var_dump($value);
}
// string(3) "foo"
// string(3) "bar"
// string(3) "baz"
// string(3) "qux"

foreach ($foo as $value) {
    var_dump($value);
}
// PHP Fatal error:  Uncaught Exception: Cannot traverse an already closed generator.

$foo = new Foo();
foreach ($foo as $value) {
    var_dump($value);
}
// string(3) "foo"
// string(3) "bar"
// string(3) "baz"
// string(3) "qux"

foreach ($foo as $value) {
    var_dump($value);
}
// string(3) "foo"
// string(3) "bar"
// string(3) "baz"
// string(3) "qux"

```

上例中的 `example.txt` 文件内容：

```
foo
bar
baz
qux
```

