生成器与 Iterator 对象比较

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

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

results matching ""

    No results matching ""