-
-
Save auroraeosrose/53201bd866b30cea523a to your computer and use it in GitHub Desktop.
Some braindumping - pseudocode
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Garnet/CMS/Core; | |
class App { | |
use Signals, Logging, Config; | |
protected $signals = array('configure', 'loadPluggables', 'startup', 'shutdown', 'run', 'route'); | |
public function __construct() { | |
$this->register($this->signals); | |
$this->emit('configure'); | |
$this->emit('loadPluggables'); | |
$this->emit('startup'); | |
} | |
public function run() { | |
$this->emit('run'); | |
$this->emit('route'); | |
} | |
public function __destruct() { | |
$this->emit('unloadPluggables'); | |
$this->emit('shutdown'); | |
} | |
// other auto handlers for items might be here | |
public function __doConfigure() { | |
// magically gets called and does configuration nonsense? | |
} | |
} | |
/** | |
* Emit the signal - runs 7 stages | |
* | |
* 1 - Run all slots attached to a signal (default slot) marked RUN_FIRST | |
* 2 - Run any hooks - slots assigned to ALL instances for a specific signal | |
* 3 - Run all normal slots marked RUN_FIRST | |
* 4 - Run all the default slots marked RUN_LAST | |
* 5 - Run all the normal slots marked RUN_LAST | |
* 6 - Run all the normal slots marked RUN_CLEANUP | |
* 7 - Run all slots attached to a signal (default slot) marked RUN_CLEANUP | |
* note these always run regardless of bubble | |
* | |
* This series is almost identical to the Gobjects emission list | |
* Slots are called in the order they were connected in - any slot | |
* may stop emission of a stage by returning a TRUE value except in default cleanup | |
* | |
* If, at any point during emission except for the cleanup state, one of the closures or emission hook emits | |
* the same signal on the same instance, emission is restarted from the RUN_FIRST state | |
* | |
* @return void | |
*/ | |
public function emit($name) { | |
if (is_null($this->state)) { | |
$this->state = array(); | |
} | |
// retrieve our signal from our hash map | |
$signal = self::getSignal($name); | |
if (is_null($signal)) { | |
// bail, bad signal | |
throw new InvalidArgumentException('Signal ' . $name . ' is not a registered signal of ' . get_class($this)); | |
} | |
// fast check for recursion - if we're in an emit and signal matches | |
// signal then we set the state to restart and return | |
if (isset($this->state[$name]) && $this->state[$name] === self::EMISSION_RUN) { | |
$this->state[$name] = self::EMISSION_RESTART; | |
return; | |
} | |
// check for blocked signal | |
if ($signal->isBlocked()) { | |
$this->state[$signal] = self::EMISSION_STOP; | |
return; | |
} | |
// prepare args | |
$args = func_get_args(); | |
// take off signal name | |
array_shift($args); | |
// set up some other variables | |
$slot = $signal->getSlot(); | |
$class = get_class($this); | |
if ($slot) { | |
$position = $slot->getPosition(); | |
} else { | |
$position = null; | |
} | |
// Where we restart emissions for recursion | |
emit_restart: | |
$bubble = false; | |
$this->state[$name] = self::EMISSION_RUN; | |
// stage 1: RUN_FIRST default handlers | |
if ($position == Slot::RUN_FIRST) { | |
// magic of closures and __invoke | |
$slot($args); | |
// handle our possible states | |
if ($this->state[$name] === self::EMISSION_STOP) { | |
goto emit_cleanup; | |
} | |
if ($this->state[$name] === self::EMISSION_RESTART) { | |
goto emit_restart; | |
} | |
} | |
// stage 2 - run any hooked slots | |
if (isset(self::$hooks[$class]) && isset(self::$hooks[$class][$name])) { | |
foreach(self::$hooks[$class][$name] as $slot => $hook_args) { | |
$bubble = $slot($args + $slot_args); | |
$bubble = $signal->callAccumulator($bubble); | |
if ($bubble === true || $this->state[$name] === self::EMISSION_STOP) { | |
goto emit_cleanup; | |
} else if ($this->state[$name] === self::EMISSION_RESTART) { | |
goto emit_restart; | |
} | |
} | |
unset($slot, $hook_args); | |
} | |
// stage 3 - normally connected handlers not marked with runlast | |
if (isset($this->slots[$name])) { | |
foreach($this->slots[$name] as $slot) { | |
if ($slot->getPosition() !== SLOT::RUN_FIRST) { | |
continue; | |
} | |
$bubble = $slot($args + $this->slots[$name][$slot]); | |
$bubble = $signal->callAccumulator($bubble); | |
// handle our possible states | |
if ($bubble === true || $this->state[$name] === self::EMISSION_STOP) { | |
goto emit_cleanup; | |
} else if ($this->state[$name] === self::EMISSION_RESTART) { | |
goto emit_restart; | |
} | |
} | |
unset($slot); | |
} | |
// stage 4 - RUN_LAST default handlers | |
if ($position == Slot::RUN_LAST) { | |
// magic of closures and __invoke | |
$slot($args); | |
// handle our possible states | |
if ($this->state[$name] === self::EMISSION_STOP) { | |
goto emit_cleanup; | |
} | |
if ($this->state[$name] === self::EMISSION_RESTART) { | |
goto emit_restart; | |
} | |
} | |
// stage 5 - connected slots marked RUN_LAST | |
if (isset($this->slots[$name])) { | |
foreach($this->slots[$name] as $slot) { | |
if ($slot->getPosition() !== SLOT::RUN_LAST) { | |
continue; | |
} | |
$bubble = $slot($args + $this->slots[$name][$slot]); | |
$bubble = $signal->callAccumulator($bubble); | |
// handle our possible states | |
if ($bubble === true || $this->state[$name] === self::EMISSION_STOP) { | |
goto emit_cleanup; | |
} else if ($this->state[$name] === self::EMISSION_RESTART) { | |
goto emit_restart; | |
} | |
} | |
unset($slot); | |
} | |
// stage 6 - connected slots marked RUN_CLEANUP | |
if (isset($this->slots[$name])) { | |
foreach($this->slots[$name] as $slot) { | |
if ($slot->getPosition() !== SLOT::RUN_CLEANUP) { | |
continue; | |
} | |
$bubble = $slot($args + $this->slots[$name][$slot]); | |
$bubble = $signal->callAccumulator($bubble); | |
// handle our possible states | |
if ($bubble === true || $this->state[$name] === self::EMISSION_STOP) { | |
goto emit_cleanup; | |
} else if ($this->state[$name] === self::EMISSION_RESTART) { | |
goto emit_restart; | |
} | |
} | |
unset($slot); | |
} | |
// stage 7 - RUN_CLEANUP default slots | |
emit_cleanup: | |
if ($position == Slot::RUN_CLEANUP) { | |
// magic of closures and __invoke | |
$slot($args); | |
$bubble = $signal->callAccumulator($bubble); | |
// handle our possible states | |
if ($this->state[$name] === self::EMISSION_RESTART) { | |
goto emit_restart; | |
} | |
} | |
$this->state[$name] = self::EMISSION_STOP; | |
return $bubble; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment