FSM
[ class tree: FSM ] [ index: FSM ] [ all elements ]

Source for file FSM.php

Documentation is available at FSM.php

  1. <?php
  2. /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */
  3. /* +----------------------------------------------------------------------+
  4.  * | PHP Version 4                                                        |
  5.  * +----------------------------------------------------------------------+
  6.  * | Copyright (c) 1997-2004 The PHP Group                                |
  7.  * +----------------------------------------------------------------------+
  8.  * | This source file is subject to version 2.02 of the PHP license,      |
  9.  * | that is bundled with this package in the file LICENSE, and is        |
  10.  * | available at through the world-wide-web at                           |
  11.  * | http://www.php.net/license/2_02.txt.                                 |
  12.  * | If you did not receive a copy of the PHP license and are unable to   |
  13.  * | obtain it through the world-wide-web, please send a note to          |
  14.  * | license@php.net so we can mail you a copy immediately.               |
  15.  * +----------------------------------------------------------------------+
  16.  * | Authors: Jon Parise <jon@php.net>                                    |
  17.  * +----------------------------------------------------------------------+
  18.  *
  19.  * $Id: FSM.php,v 1.13 2005/01/08 22:43:25 jon Exp $
  20.  */
  21.  
  22. /**
  23.  * This class implements a Finite State Machine (FSM).
  24.  *
  25.  * In addition to maintaining state, this FSM also maintains a user-defined
  26.  * payload, therefore effectively making the machine a Push-Down Automata
  27.  * (a finite state machine with memory).
  28.  *
  29.  * This code is based on Noah Spurrier's Finite State Machine (FSM) submission
  30.  * to the Python Cookbook:
  31.  *
  32.  *      http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146262
  33.  *
  34.  * @author  Jon Parise <jon@php.net>
  35.  * @version $Revision: 1.13 $
  36.  * @package FSM
  37.  *
  38.  * @example rpn.php     A Reverse Polish Notation (RPN) calculator.
  39.  */
  40. class FSM
  41. {
  42.     /**
  43.      * Represents the initial state of the machine.
  44.      *
  45.      * @var string 
  46.      * @see $_currentState
  47.      * @access private
  48.      */
  49.     var $_initialState '';
  50.  
  51.     /**
  52.      * Contains the current state of the machine.
  53.      *
  54.      * @var string 
  55.      * @see $_initialState
  56.      * @access private
  57.      */
  58.     var $_currentState '';
  59.  
  60.     /**
  61.      * Contains the payload that will be passed to each action function.
  62.      *
  63.      * @var mixed 
  64.      * @access private
  65.      */
  66.     var $_payload = null;
  67.  
  68.     /**
  69.      * Maps (inputSymbol, currentState) --> (action, nextState).
  70.      *
  71.      * @var array 
  72.      * @see $_initialState, $_currentState
  73.      * @access private
  74.      */
  75.     var $_transitions = array();
  76.  
  77.     /**
  78.      * Maps (currentState) --> (action, nextState).
  79.      *
  80.      * @var array 
  81.      * @see $_inputState, $_currentState
  82.      * @access private
  83.      */
  84.     var $_transitionsAny = array();
  85.  
  86.     /**
  87.      * Contains the default transition that is used if no more appropriate
  88.      * transition has been defined.
  89.      *
  90.      * @var array 
  91.      * @access private
  92.      */
  93.     var $_defaultTransition = null;
  94.  
  95.  
  96.     /**
  97.      * This method constructs a new Finite State Machine (FSM) object.  In
  98.      * addition to defining the machine's initial state, a "payload" may also
  99.      * be specified.  The payload represents a variable that will be passed
  100.      * along to each of the action functions.  If the FSM is being used for
  101.      * parsing, the payload is often a array that is used as a stack.
  102.      *
  103.      * @param   string  $initialState   The initial state of the FSM.
  104.      * @param   mixed   $payload        A payload that will be passed to each
  105.      *                                   action function.
  106.      */
  107.     function FSM($initialState&$payload)
  108.     {
  109.         $this->_initialState $initialState;
  110.         $this->_currentState $initialState;
  111.         $this->_payload &$payload;
  112.     }
  113.  
  114.     /**
  115.      * This method resets the FSM by setting the current state back to the
  116.      * initial state (set by the constructor).
  117.      */
  118.     function reset()
  119.     {
  120.         $this->_currentState $this->_initialState;
  121.     }
  122.  
  123.     /**
  124.      * This method adds a new transition that associates:
  125.      *
  126.      *      (symbol, currentState) --> (nextState, action)
  127.      *
  128.      * The action may be set to NULL, in which case the processing routine
  129.      * will ignore the action and just set the next state.
  130.      *
  131.      * @param   string  $symbol         The input symbol.
  132.      * @param   string  $state          This transition's starting state.
  133.      * @param   string  $nextState      This transition's ending state.
  134.      * @param   string  $action         The name of the function to invoke
  135.      *                                   when this transition occurs.
  136.      *
  137.      * @see     addTransitions()
  138.      */
  139.     function addTransition($symbol$state$nextState$action = null)
  140.     {
  141.         $this->_transitions["$symbol,$state"= array($nextState$action);
  142.     }
  143.  
  144.     /**
  145.      * This method adds the same transition for multiple different symbols.
  146.      *
  147.      * @param   array   $symbols        A list of input symbols.
  148.      * @param   string  $state          This transition's starting state.
  149.      * @param   string  $nextState      This transition's ending state.
  150.      * @param   string  $action         The name of the function to invoke
  151.      *                                   when this transition occurs.
  152.      *
  153.      * @see     addTransition()
  154.      */
  155.     function addTransitions($symbols$state$nextState$action = null)
  156.     {
  157.         foreach ($symbols as $symbol{
  158.             $this->addTransition($symbol$state$nextState$action);
  159.         }
  160.     }
  161.  
  162.     /**
  163.      * This method adds a new transition that associates:
  164.      *
  165.      *      (currentState) --> (nextState, action)
  166.      *
  167.      * The processing routine checks these associations if it cannot first
  168.      * find a match for (symbol, currentState).
  169.      *
  170.      * @param   string  $state          This transition's starting state.
  171.      * @param   string  $nextState      This transition's ending state.
  172.      * @param   string  $action         The name of the function to invoke
  173.      *                                   when this transition occurs.
  174.      *
  175.      * @see     addTransition()
  176.      */
  177.     function addTransitionAny($state$nextState$action = null)
  178.     {
  179.         $this->_transitionsAny[$state= array($nextState$action);
  180.     }
  181.  
  182.     /**
  183.      * This method sets the default transition.  This defines an action and
  184.      * next state that will be used if the processing routine cannot find a
  185.      * suitable match in either transition list.  This is useful for catching
  186.      * errors caused by undefined states.
  187.      *
  188.      * The default transition can be removed by setting $nextState to NULL.
  189.      *
  190.      * @param   string  $nextState      The transition's ending state.
  191.      * @param   string  $action         The name of the function to invoke
  192.      *                                   when this transition occurs.
  193.      */
  194.     function setDefaultTransition($nextState$action)
  195.     {
  196.         if (is_null($nextState)) {
  197.             $this->_defaultTransition = null;
  198.             return;
  199.         }
  200.  
  201.         $this->_defaultTransition = array($nextState$action);
  202.     }
  203.  
  204.     /**
  205.      * This method returns (nextState, action) given an input symbol and
  206.      * state.  The FSM is not modified in any way.  This method is rarely
  207.      * called directly (generally only for informational purposes).
  208.      *
  209.      * If the transition cannot be found in either of the transitions lists,
  210.      * the default transition will be returned.  Note that it is possible for
  211.      * the default transition to be set to NULL.
  212.      *
  213.      * @param   string  $symbol         The input symbol.
  214.      *
  215.      * @return  mixed   Array representing (nextState, action), or NULL if the
  216.      *                   transition could not be found and not default
  217.      *                   transition has been defined.
  218.      */
  219.     function getTransition($symbol)
  220.     {
  221.         $state $this->_currentState;
  222.  
  223.         if (!empty($this->_transitions["$symbol,$state"])) {
  224.             return $this->_transitions["$symbol,$state"];
  225.         elseif (!empty($this->_transitionsAny[$state])) {
  226.             return $this->_transitionsAny[$state];
  227.         else {
  228.             return $this->_defaultTransition;
  229.         }
  230.     }
  231.  
  232.     /**
  233.      * This method is the main processing routine.  It causes the FSM to
  234.      * change states and execute actions.
  235.      *
  236.      * The transition is determined by calling getTransition() with the
  237.      * provided symbol and the current state.  If no valid transition is found,
  238.      * process() returns immediately.
  239.      *
  240.      * The action callback may return the name of a new state.  If one is
  241.      * returned, the current state will be updated to the new value.
  242.      *
  243.      * If no action is defined for the transition, only the state will be
  244.      * changed.
  245.      *
  246.      * @param   string  $symbol         The input symbol.
  247.      *
  248.      * @see     processList()
  249.      */
  250.     function process($symbol)
  251.     {
  252.         $transition $this->getTransition($symbol);
  253.  
  254.         /* If a valid array wasn't returned, return immediately. */
  255.         if (!is_array($transition|| (count($transition!= 2)) {
  256.             return;
  257.         }
  258.  
  259.         /* Update the current state to this transition's exit state. */
  260.         $this->_currentState $transition[0];
  261.  
  262.         /* If an action for this transition has been specified, execute it. */
  263.         if (!empty($transition[1])) {
  264.             $state call_user_func_array($transition[1],
  265.                                           array($symbol&$this->_payload));
  266.  
  267.             /* If a new state was returned, update the current state. */
  268.             if (!empty($state&& is_string($state)) {
  269.                 $this->_currentState $state;
  270.             }
  271.         }
  272.     }
  273.  
  274.     /**
  275.      * This method processes a list of symbols.  Each symbol in the list is
  276.      * sent to process().
  277.      *
  278.      * @param   array   $symbols        List of input symbols to process.
  279.      */
  280.     function processList($symbols)
  281.     {
  282.         foreach ($symbols as $symbol{
  283.             $this->process($symbol);
  284.         }
  285.     }
  286. }
  287.  
  288. ?>

Documentation generated on Mon, 11 Mar 2019 14:12:30 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.