FSM(有限状态机)是啥?
有限状态机(英语:finite-state machine,缩写:FSM)又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。
详细请看维基百科,FSM(http://zh.wikipedia.org/wiki/%E6%9C%89%E9%99%90%E7%8A%B6%E6%80%81%E6%9C%BA)。自动机编程(http://zh.wikipedia.org/wiki/%E8%87%AA%E5%8A%A8%E6%9C%BA%E7%BC%96%E7%A8%8B)
简单来说,这玩意用于事物有多种状态,主要在状态之间变来变去的场景,你很想用个goto跳到上面的某个if的地方。 比如一个魔方,比如形式语言分析,比如魔兽世界战士战斗姿态防御姿态狂暴姿态角斗士姿态,比如模拟一堆电路元件…… 通常对于此类问题,如果输入条件是可以完全预知的,那么可以通过写while里套一堆if then,或者switch case来处理,或者通过构造一个“图”的数据结构更弹性些。(当然也有某些比较狂热的方式比如弄无数层对象来折腾程序员自己和机器)但是这些方式不够接近机器与数学的本质,也难以应对未知条件。 今天,为寻求远古强大的元素力量,我将带你深入不毛之地,研究研究php里pear-FSM。
下载地址是
http://pear.php.net/package/FSM
作者后来也把项目迁移到了github,目前版本都是1.3.1
https://github.com/pear/FSM
Current Release | |
---|---|
1.3.1 (stable) was released on 2011-02-16 (Changelog) |
what? 看起来距今有些年代?没关系,C语言还在,很多60年代的技术,80年代的技术也至今经典不息。我们研究的是远古力量,内心要平静,不要有私心杂念。
下载后解开包看看。首先要看docs\guide.txt,请用能区分换行的文本编辑器看,比如notepad++。
这段英文主要说了这么回事情:
Building a Finite State Machine
===============================
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.
这玩意咋用? 首先要弄出个带点起码状态的状态机。然后定义允许的状态转换方式。用符号+回调函数方式来定义转换。 定义好以后, 输入的信息就会经过符号的匹配来对应的转换。(强心针:晕了? 看看这句 $state=$arr['mySymbol']; 这样就是一种简单的符号-状态匹配,当然本文里实现的更复杂点点,不过也是通过数组查询来调用对应函数) 如果输入的符号,对应当前状态可以转换到别的状态,就转状态;有指明对应状态转换对应的回调函数就调用这个函数。
(强心针2: 又晕了? 说白就是这么回事。假如你脸朝向是个状态,现在向左(状态1)看着自己的屏幕。给自己下了死命令,除非右边来美女(符号)否则不扭头(状态转换)。然后右边来了个男的(符号),死命令查找不到这个性取向,不扭头。来了个美女(符号),查询死命令有这个状态转换,则扭头(状态转换),并且调用定义好的回调函数(打招呼,吹口哨,耍流氓……自便)
Creating a New FSM Object
-------------------------
Start by including the FSM package in your script::
下面是怎么用这个玩意的具体实战。第一步,php require会用?下面这句是php的,把fsm.php require进来。
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.
然后new 个FSM 对象出来,这new不能随便乱new, 脖子朝向不能null是吧? 得new出来个初始状态和负载变量。
负载变量用来把状态信息传递给所有回调函数,并且不用全局变量。说白了,看人用自己眼睛看,不要借助其他人的目光。
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);
如此简易的php代码看起来蛮轻松的。
Defining Transitions
--------------------
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)
{
echo "First Transition\n";
}
function SecondCallback($symbol, $payload)
{
echo "Second Transition\n";
}
$fsm->addTransition('FIRST', 'START', 'MIDDLE', 'FirstCallback');
$fsm->addTransition('SECOND', 'MIDDLE', 'END', 'SecondCallback');
从代码和上面说到的要做的事情,可以猜到
addTransition的参数,第2,3就是表示从哪个状态到哪个状态。第4个参数是回调函数名字。
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.
现在我们的状态机有了3个状态(开始,中间过程,结束),2个符号(FIREST和SECEND),2个状态转换(开始->中间过程,中间过程->结束),并且有了状态转换对应的回调函数。接下来是过程转换实例:
::
$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
这样就是先后执行了从开始到中间过程,从中间过程到结束两个过程的转换。
Setting Default Transitions
---------------------------
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.
指定默认转换
现在我们来设定个默认转换。默认转换用来在符号匹配不了时调用(switch..case..default 懂?)。在我们例子里
默认认为是默认转换会出发错误,并且输出警告给用户。
::
function ErrorCallback($symbol, $payload)
{
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.
这样一来,因为在开始状态下,没有定义SECOND对应的从开始状态到其他状态的转换,所以就报错了。接下来由于状态回归了“开始”,所以调用“FIRST”符号对应转换是可以按期望工作的。
Plotting a State Machine
========================
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.
::
接下来是状态可视化工作。这个FSM包支持用"Image_GraphViz"包来输出状态机情况。只要new个FSM_GraphViz对象出来然后调用其实例的export就可以输出个图来看看了。
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:: 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
下面是联系方式,有想和作者联系的请自便。
Development and Support
=======================
Reporting Problems and Suggestions
----------------------------------
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
Coming Soon
-----------
This section contains a list of "todo" items that will hopefully be addressed
in future releases.
- *No items at this time.*
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:
接下来,来玩玩例子。