:Author: Jon Parise :Contact: jon@php.net
.. contents:: Contents .. section-numbering::
The FSM Package
implements a Finite State Machine
. In addition to
maintaining state, this FSM also manages a user-defined payload, therefore
effectively making the machine a Pushdown Automaton
_ (a finite state machine
with memory).
This code is based largely on Noah Spurrier's excellent FSM Python class
_.
.. _FSM Package: http://pear.php.net/package/FSM .. _Finite State Machine: http://wikipedia.org/wiki/Finite_state_machine .. _Pushdown Automaton: http://wikipedia.org/wiki/Push-down_automata .. _FSM Python class: http://www.noah.org/python/FSM/
The first step in building a Finite State Machine involves listing the finite set of states. Then, all of the permissible transitions between these states must be defined. A symbol and an optional callback function are associated with each transition. The input processing routine will attempt to match its current symbol against the list of registered transitions. If a transition from the current state using that symbol is found, the machine will move to the new state specified by the transition and, if one has been specified, the associated callback function will be invoked.
Start by including the FSM package in your script::
require 'FSM.php';
When constructing a new FSM object, you must specify the machine's initial state and provide a payload variable. The payload will be passed to all of the callback functions, supplying them with state information without (ab)using global variables.
In this example, we pass an array representing a stack as the payload. The
machine's initial state is set to START
.
::
$stack = array();
$fsm = new FSM('START', $stack);
We'll need to define some transitions in order to make our machine useful.
Let's assume our machine has two additional states: MIDDLE
and END
.
Here's how we would define transitions to move us from START
to MIDDLE
and from MIDDLE
to END
::
function FirstCallback($symbol, &$payload, $currentState, $nextState)
{
echo "First Transition\n";
}
function SecondCallback($symbol, &$payload, $currentState, $nextState)
{
echo "Second Transition\n";
}
$fsm->addTransition('FIRST', 'START', 'MIDDLE', 'FirstCallback');
$fsm->addTransition('SECOND', 'MIDDLE', 'END', 'SecondCallback');
Our machine is now aware of three states (START
, MIDDLE
, and END
)
and two symbols (FIRST
and SECOND
). Two transitions (START
to
MIDDLE
and MIDDLE
to END
) have been defined and associated with
callbacks. The following code will process the symbols FIRST
and
SECOND
and move us from our initial state (START
) through the
MIDDLE
state to the END
state.
::
$fsm->process('FIRST');
$fsm->process('SECOND');
The processing routine will invoke our two callbacks along the way, as well, resulting in the following being printed::
First Transition
Second Transition
Now we'll set up a default transition. This transition will be used whenever the processing routine cannot find a better match for the current state and symbol. For our example, we'll consider this an error and print a warning for the user.
::
function ErrorCallback($symbol, &$payload, $currentState, $nextState)
{
echo "This symbol does not compute: $symbol\n";
}
$fsm->setDefaultTransition('START', 'ErrorCallback');
Now let's process our symbols in an unexcepted order::
$fsm->process('SECOND');
$fsm->process('FIRST');
Because the SECOND
transition doesn't specify START
as its initial
state, the default transition will be used and the error callback will be
invoked. The FIRST
transition will work as expected, however, because the
machine will still be in the START
state.
The FSM package optionally supports the ability to plot a machine's states
with the help of the Image_GraphViz
_ package. Doing so is as simple as
creating a new FSM_GraphViz
object using an existing state machine
instance and then exporting the graph.
::
require_once 'FSM/GraphViz.php';
$converter = new FSM_GraphViz($fsm);
$graph = $converter->export();
The resulting graph object is an Image_GraphViz
instance. To export the
graph as an image, use the image()
method::
$graph->image('png');
This will produce an image similar to the following:
.. figure:: https://raw.github.com/pear/FSM/master/docs/graphviz.png :alt: Example State Machine Plot
Consult the Image_GraphViz documentation
_ for additional usage information.
.. _Image_GraphViz: http://pear.php.net/package/Image_GraphViz .. _Image_GraphViz documentation: http://pear.php.net/package/Image_GraphViz/docs
If you run into a problem or would like to make a suggestion, please use the
PEAR Bug Tracker
_. Feel free to contact me directly for other issues, but
please try to use the bug tracker whenever possible so that others in the
community will benefit from your feedback and my responses.
Open Bugs
_Report a New Bug
_.. _PEAR Bug Tracker: http://pear.php.net/bugs/ .. _Open Bugs: http://pear.php.net/package/FSM/bugs .. _Report a New Bug: http://pear.php.net/bugs/report.php?package=FSM
This section contains a list of "todo" items that will hopefully be addressed in future releases.
If you have feature suggestions, please submit them using the PEAR Bug Tracker
_.
.. vim: syntax=rst tabstop=4 shiftwidth=4 softtabstop=4 expandtab textwidth=78: