rfc:generators

Differences

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

Link to this comparison view

rfc:generators [2012/09/01 19:22]
nikic Change state to "Implemented"
rfc:generators [2013/04/06 13:27] (current)
nikic Note that cloning support was removed
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: 2013/04/06 13:27 by nikic