rfc:generators

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Last revisionBoth sides next revision
rfc:generators [2012/09/01 17:22] – Change state to "Implemented" nikicrfc:generators [2013/04/06 11:27] – Note that cloning support was removed nikic
Line 189: Line 189:
          
     mixed send(mixed $value);     mixed send(mixed $value);
 +    mixed throw(Exception $exception);
 } }
 </code> </code>
Line 228: Line 229:
   * ''next'': Resumes the generator (unless the generator is already closed).   * ''next'': Resumes the generator (unless the generator is already closed).
   * ''send'': Sets the return value of the ''yield'' expression and resumes the generator (unless the generator is already closed). (More in the "Sending values" section.)   * ''send'': Sets the return value of the ''yield'' expression and resumes the generator (unless the generator is already closed). (More in the "Sending values" section.)
 +  * ''throw'': Throws an exception at the current suspension point in the generator. (More in the "Throwing into the generator" section.)
  
 ==== Yield syntax ==== ==== Yield syntax ====
Line 392: Line 394:
 $logger->send('Foo'); $logger->send('Foo');
 $logger->send('Bar'); $logger->send('Bar');
 +</code>
 +
 +==== Throwing into the generator ====
 +
 +Exceptions can be thrown into the generator using the ''Generator::throw()'' method. This will throw an exception in the generator's execution
 +context and then resume the generator. It is roughly equivalent to replacing the current ''yield'' expression with a ''throw'' statement and
 +resuming then. If the generator is already closed the exception will be thrown in the callers context instead (which is equivalent to replacing
 +the ''throw()'' call with a ''throw'' statement). The ''throw()'' method will return the next yielded value (if the exception is caught and no
 +other exception is thrown).
 +
 +An example of the functionality:
 +
 +<code php>
 +function gen() {
 +    echo "Foo\n";
 +    try {
 +        yield;
 +    } catch (Exception $e) {
 +        echo "Exception: {$e->getMessage()}\n";
 +    }
 +    echo "Bar\n";
 +}
 +
 +$gen = gen();
 +$gen->rewind();                     // echos "Foo"
 +$gen->throw(new Exception('Test')); // echos "Exception: Test"
 +                                    // and "Bar"
 </code> </code>
  
Line 430: Line 459:
 ==== Cloning a generator ==== ==== Cloning a generator ====
  
-Generators can be cloned, thus leaving two independent ''Generator'' objects with the same stateThis behavior can for example be +Generators cannot be cloned.
-used to create a ''rewindable'' function, which would make the passed generator rewindable: +
- +
-<code php> +
-class RewindableGenerator implements Iterator { +
-    protected $original; +
-    protected $current; +
-     +
-    public function __construct(Generator $generator) { +
-        $this->original = $generator; +
-        $this->current = null; +
-    } +
-     +
-    public function rewind() { +
-        if ($this->current) { $this->current->close();+
-        $this->current = clone $this->original; +
-        $this->current->rewind(); +
-    } +
-     +
-    public function valid() { +
-        if (!$this->current) { $this->current = clone $this->original;+
-        return $this->current->valid(); +
-    } +
-     +
-    public function current() { +
-        if (!$this->current) { $this->current = clone $this->original;+
-        return $this->current->current(); +
-    } +
-     +
-    public function key() { +
-        if (!$this->current) { $this->current = clone $this->original;+
-        return $this->current->key(); +
-    } +
-     +
-    public function next() { +
-        if (!$this->current) { $this->current = clone $this->original;+
-        $this->current->next(); +
-    } +
-     +
-    public function send($value) { +
-        if (!$this->current) { $this->current = clone $this->original;+
-        return $this->current->send($value); +
-    } +
-     +
-    public function close() { +
-        $this->original->close(); +
-        if ($this->current) { +
-            $this->current->close(); +
-        } +
-    } +
-+
- +
-function rewindable(Generator $generator) { +
-    return new RewindableGenerator($generator); +
-+
-</code> +
- +
-It can be then used as follows: +
- +
-<code php> +
-function xrange($start, $end, $step = 1) { +
-    for ($i = $start; $i <= $end; $i += $step) { +
-        yield $i; +
-    } +
-+
- +
-$range = rewindable(xrange(0, 5)); +
-foreach ($range as $i) { +
-    echo $i, "\n"; +
-+
-foreach ($range as $i) { +
-    echo $i, "\n"; +
-+
-</code>+
  
-This will correctly output the 0..5 range twice.+Support for cloning was included in the initial version, but removed in PHP 5.5 Beta 3 due to implementational difficulties, unclear semantics and no particularly convincing use cases.
  
 ==== Closing a generator ==== ==== Closing a generator ====
rfc/generators.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1