Skip to content

Instantly share code, notes, and snippets.

@dadamssg
Last active December 31, 2015 23:09
Show Gist options
  • Save dadamssg/8057913 to your computer and use it in GitHub Desktop.
Save dadamssg/8057913 to your computer and use it in GitHub Desktop.
<?php
$obj = new \stdClass;
$obj->x = '';
$first = function() use ($obj) {
$obj->x .= ' 1 ';
yield ControlFlow::NEXT;
$obj->x .= ' 2 ';
};
$second = function() use ($obj){
$obj->x .= ' 3 ';
yield ControlFlow::NEXT;
$obj->x .= ' 4 ';
};
$third = function() use ($obj){
$obj->x .= ' 5 ';
$obj->x .= ' 6 ';
return ControlFlow::NEXT;
};
$fourth = function() use ($obj){
$obj->x .= ' 7 ';
$obj->x .= ' 8 ';
return ControlFlow::NEXT;
};
$flow = new ControlFlow;
$flow->queue($first())
->queue($second())
->queue($third)
->queue($fourth);
$flow->run();
class ControlFlow
{
const NEXT = 'NEXT';
/**
* @var array
*/
protected $queued = [];
/**
* @var array
*/
protected $initiated = [];
/**
* Add to the ControlFlow
*
* @param \Closure|\Generator $item
* @return $this
* @throws \InvalidArgumentException
*/
public function queue($item)
{
if ( ! $item instanceof \Closure && ! $item instanceof \Generator) {
throw new \InvalidArgumentException('Queued item must be a \Closure or \Generator');
}
$this->queued[] = $item;
return $this;
}
/**
* Run all queued
*
* @return void
*/
public function run()
{
foreach ($this->queued as $queued) {
$this->runQueued($queued);
}
$this->reset();
}
/**
* Run a queued \Closure or \Generator
*
* @param \Closure|\Generator $queued
* @return void
*/
private function runQueued($queued)
{
if (in_array($queued, $this->initiated, true)) return;
if ($queued instanceof \Generator) {
$this->runGenerator($queued);
} elseif ($queued instanceof \Closure) {
$this->runClosure($queued);
}
}
/**
* Run a queued closure
*
* @param \Closure $closure
* @return void
*/
private function runClosure(\Closure $closure)
{
$this->initiated[] = $closure;
if ($closure() === self::NEXT) {
$this->initiateNext();
}
}
/**
* Run a queued Generator
*
* @param \Generator $generator
* @return void
*/
private function runGenerator(\Generator $generator)
{
$this->initiated[] = $generator;
foreach ($generator as $result) {
if ($result === self::NEXT) {
$this->initiateNext();
}
}
}
/**
* Initiate the next queued
*
* @return void
*/
private function initiateNext()
{
$next = current($this->queued);
next($this->queued);
$this->runQueued($next);
}
/**
* Reset to run again
*
* @return void
*/
public function reset()
{
reset($this->queued);
$this->initiated = [];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment