tmilos / light-fsm
轻量级且简单的有限状态机,具有优秀的API,支持自动工作流程和外部状态,可导出DOT图
Requires (Dev)
- phpunit/phpunit: ~4.8
- satooshi/php-coveralls: ~0.6
This package is not auto-updated.
Last update: 2024-09-14 19:03:55 UTC
README
有限状态机(FSM)PHP库。在PHP代码中直接创建状态机和基于轻量级状态机的流程。
$phoneCall = new StateMachine(State::OFF_HOOK); $phoneCall->configure(State::OFF_HOOK) ->permit(Event::CALL_DIALED, State::RINGING); $phoneCall->configure(State::RINGING) ->permit(Event::HUNG_UP, State::OFF_HOOK) ->permit(Event::CALL_CONNECTED, State::CONNECTED); $phoneCall->configure(State::CONNECTED) ->onEntry([$this, 'startTimer']) ->onExit([$this, 'stopTimer']) ->permit(Event::HUNG_UP, State::OFF_HOOK) ->permit(Event::PLACE_ON_HOLD, State::ON_HOLD); $phoneCall->fire(Event::CALL_DIALED); $this->assertEquals(State::RINGING, $phoneCall->getCurrentState());
此项目以及上面的示例,受到了stateless的启发。
特性
- 字符串或整型的状态和触发事件
- 带附加数据的触发事件
- 分层状态
- 状态进入/退出事件
- 检查
- 守卫回调以支持条件转换
- 能够在外部存储状态(例如,在ORM跟踪的属性中)
- 导出为DOT图
带附加数据的触发事件
事件可以通过StateMachine::fire($event, $data)
带附加数据触发,这些数据将被传递并可用于进入/退出和守卫监听器,以便它们可以根据它来建立逻辑。
分层状态
在下面的示例中,ON_HOLD
状态是CONNECTED
状态的子状态。这意味着ON_HOLD
调用仍然连接。
$phoneCall->configure(State::ON_HOLD) ->subStateOf(State::CONNECTED) ->permit(Event::CALL_CONNECTED, State::CONNECTED);
除了StateMachine::getCurrentState()
方法将报告精确的当前状态外,还提供了一个isInState($state)
方法。isInState($state)
将考虑子状态,所以如果上述示例处于ON_HOLD
状态,isInState(State::CONNECTED)
也会评估为true
。
进入/退出事件
在示例中,startTimer()
方法将在通话连接时执行。当通话完成时,将执行stopTimer()
。
当通话在CONNECTED
和ON_HOLD
状态之间移动时,由于ON_HOLD
状态是CONNECTED
状态的子状态,这些监听器可以区分子状态,并根据第一个$isSubState
参数确定通话仍然连接。
外部状态存储
为了持久性目的监听状态变化,例如使用某些ORM工具,将监听器回调传递给StateMachine
构造函数。
$stateObject = $orm-find(); $stateMachine = new StateMachine( function () use ($stateObject) { return $stateObject->getValue(); }, function ($state) use ($stateObject) { $stateObject->setValue($state); $orm->persist($stateObject); } );
在这种情况下,当StateMachine
用两个回调构建时,状态完全外部化,并且每次StateMachine
需要当前状态时,第一个回调将被调用,每次状态变化时,第二个回调将被调用。
检查
状态机可以通过StateMachine::getPermittedTriggers()
方法提供可以在当前状态下成功触发的触发事件的列表。
守卫子句
状态机将根据守卫子句在多个转换之间进行选择,例如。
$phoneCall->configure(State::OFF_HOOK) .permit(Trigger::CALL_DIALLED, State::RINGING, function ($data) { return IsValidNumber($data); }) .permit(Trigger::CALL_DIALLED, State::BEEPING, function ($data) { return !IsValidNumber($data); });
导出为DOT图
在运行时可视化状态机可能很有用。使用这种方法,代码是权威源,状态图是副产品,始终是最新的。
$phoneCall->configure(State::OFF_HOOK) .permit(Trigger::CALL_DIALED, State::RINGING, 'IsValidNumber'); $graph = phoneCall->toDotGraph();
StateMachine::toDotGraph()
方法返回状态机的DOT图语言字符串表示,例如。
digraph {
"off-hook" -> "ringing" [label="call-dialed [IsValidNumber]"];
}
这可以通过支持DOT图形语言的工具进行渲染,例如来自graphviz.org的dot命令行工具或viz.js。查看(http://www.webgraphviz.com)以获得即时效果。生成PDF文件的命令行示例
> dot -T pdf -o phoneCall.pdf phoneCall.dot