123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- <?php
- require_once('misc.php');
- error_reporting(E_ALL|E_STRICT);
- class fsm_result
- {
-
- public $fsm_state;
-
- public $fsm_action;
-
- public function __construct($state = NULL, $action = NULL)
- {
- $this->fsm_state = $state;
- $this->fsm_action = $action;
- }
- }
- abstract class fsm
- {
- const IDLE_EVENT = 'idle';
- const EVENT_NORMAL = 1;
- const EVENT_QUEUE = 2;
- const EVENT_SINK = 3;
- public $idle_work = TRUE;
- public $allow_actions = TRUE;
- protected $f_event_mode = fsm::EVENT_NORMAL;
- protected $f_queue = array();
-
- protected $f_state;
-
- protected $f_transitions = null;
-
- public function __construct()
- {
- $this->_check_transitions();
- reset($this->f_transitions);
- $x = each($this->f_transitions);
- $x = $x[0];
- $this->f_state = $x;
- }
-
- private function _check_transitions()
- {
- if (!isset($this->f_transitions))
- throw new Exception('No FSM processing is allowed without a transitions table');
- }
-
- public function get_state()
- {
- return $this->f_state;
- }
-
- public function get_accepted_events()
- {
- $this->_check_transitions();
- $events = array_keys($this->f_transitions[$this->f_state]);
-
- return $events;
- }
-
- public function get_accepted_outcomes($event_name)
- {
-
- $this->_check_transitions();
- if (!$this->is_event_allowed($event_name))
- throw new Exception(func_name() . ": event \"$event_name\" not allowed in state \"$this->f_state\"\n");
- $outcomes = array_keys($this->f_transitions[$this->f_state][$event_name]);
-
- return $outcomes;
- }
-
- public function is_event_allowed($event_name)
- {
-
- $this->_check_transitions();
- $ret = in_array($event_name, $this->get_accepted_events());
-
- return $ret;
- }
-
- public function is_outcome_allowed($event_name, $outcome)
- {
- $this->_check_transitions();
- if (!$this->is_event_allowed($event_name))
- return false;
- $ret = array_key_exists($outcome, $this->get_accepted_outcomes($event_name));
- return $ret;
- }
-
- public function apply_event($event_name)
- {
-
- do {
- $result = $this->apply_simple_event($event_name);
- if ($this->allow_actions)
- {
- $event_name = $result->fsm_action;
- }
- else
- {
- $event_name = NULL;
- }
- } while($event_name);
- return $result;
- }
-
- private function apply_simple_event($event_name)
- {
-
- if (($event_name == fsm::IDLE_EVENT) && !$this->idle_work)
- {
- return new fsm_result();
- }
- if (! $this->is_event_allowed($event_name))
- throw new Exception(func_name()
- . ": Event \"$event_name\" not accepted in current state \"$this->f_state\"");
- $method_name = "f_$event_name";
- $outcomes = $this->get_accepted_outcomes($event_name);
- $result = $this->$method_name();
- if (!is_object($result))
- {
- $result = new fsm_result($result, NULL);
- }
- if (!in_array($result->fsm_state, $outcomes))
- throw new Exception(func_name()
- . ": event guard. Transition on \"$event_name\" return invalid result: "
- . var_dump($result)
- . "\n");
- $this->f_state = $this->f_transitions[$this->f_state][$event_name][$result->fsm_state];
-
- return $result;
- }
-
- public function f_idle()
- {
- return TRUE;
- }
-
- public function idle()
- {
- return $this->apply_event(fsm::IDLE_EVENT);
- }
-
- public function get_event_mode()
- {
- return $this->f_event_mode;
- }
-
- public function set_event_mode($mode)
- {
- switch ($mode)
- {
- case fsm::EVENT_NORMAL :
- if (count($this->f_queue) > 0)
- {
- while ($event = array_shift($this->f_queue))
- {
- $this->apply_event($event);
- }
- }
- break;
- case fsm::EVENT_QUEUE :
- break;
- case fsm::EVENT_SINK :
- if (count($this->f_queue) > 0)
- {
- $this->f_queue = array();
- }
- break;
- default:
- throw new Exception("Trying to set unknown FSM mode $mode");
- }
- $this->f_event_mode = $mode;
- return $this->f_event_mode;
- }
- }
|