daveawb / understated
Laravel 5+ 的 PHP 有限状态机
Requires
- clue/graph: ^0.9.0
- illuminate/container: ^5.0
- illuminate/events: ^5.0
- illuminate/support: ^5.0
Requires (Dev)
- behat/behat: ^3.0
- phpspec/nyan-formatters: ^1.0
- phpspec/phpspec: ^2.2
This package is not auto-updated.
Last update: 2024-09-14 17:37:30 UTC
README
为什么使用 FSM?
FSM 允许开发者对应用中不同资源的状态进行严格控制。有许多文章详细介绍了 FSM 的概念及其功能和用途,因此这里不会过多赘述。简单来说,通过在 FSM 中管理状态,您可以集中且简洁地管理状态,而无需将其构建到业务逻辑中。该仓库中包含许多示例,可以为您展示 FSM 的实际应用。例如,Redux、Angular UI Router 和 Apollo 库中就有很好的示例。虽然这是一个针对 PHP 的实现,在 PHP 中状态问题不像其他语言或技术(基于浏览器的 JS 和更重要的是 NodeJS)那样突出,但一个精心构建的 FSM 可以减轻构建和理清大型应用的压力。
要求
- >= PHP 7.0
- (可选) >= Laravel 5.4
安装
Composer
将以下内容添加到您的 composer.json 文件中
{
"require": {
"daveawb/understated": "0.0.4"
}
}
Laravel 集成
打开 config/app.php 并注册所需的服务提供者。
'providers' => [ // ... UnderStated\Providers\UnderStatedServiceProvider::class, ]
一个简单的 FSM
use UnderStated\States\State; $builder = new UnderStated\Builders\GraphBuilder(); $fsm = $builder->create() // Create an 'on' state ->state('on', function() { /* state is on */ }) // Create an 'off' state ->state('off', function() { /* state is off */ }, State::INITIAL) // Create a transition (undirected) between the two states ->transition('on', 'off', true) // Get the FSM instance ->get();
现在我们已经解释了这些,那么如何使用它呢?
我们声明了状态 'on' 和 'off' 之间的无向转换。这意味着这两个状态都可以无限期地从一种状态转换到另一种状态。注意,将 State::INITIAL 作为第三个参数传递给 'off' 状态。这意味着当 FSM 初始化时,它将处于此状态。
在继续之前,我们需要初始化 FSM。
// Initialise using the state marked with State::INITIAL or the first state added. $fsm->initialise(); // If you want to override the initial state, pass it in to the `initialise` method $fsm->initialise('on');
现在 FSM 已经初始化,我们可以开始从一个状态转换到另一个状态。
$fsm->transition('on'); echo ($fsm->getState()->getId()); // outputs 'on' $fsm->transition('off'); echo ($fsm->getState()->getId()); // outputs 'off'
基于类的 FSM
闭包对于快速实现很有用,但在状态和转换逻辑中需要更复杂的行为时,将状态表示为类会更好。我们再次以开关示例为例。
有关使用状态和实现复杂交互的完整示例,请查看本项目包含的示例实现。
每个状态都有三个预定义的处理程序,FSM 会自动调用这些处理程序。这些是 onEnter()、onExit() 和 onReset()。
onEnter()
/** * Automatically called when this state is transitioned to. Returning false from * this method will block the transition attempt and the previous state will * remain as the active state. * * @param State $previousState * @return boolean */ public function onEnter(State $previousState)
然而,在调用上一个状态的 transition() 或 handle() 时将抛出异常,并且不会满足这两种方法。
onExit()
/** * Automatically called when this state is transitioned from. Returning false from * this method will block the transition attempt and the current state will * remain as the active state. * * @param State $nextState * @return boolean */ public function onExit(State $nextState)
此方法类似于 onEnter,在从当前状态转换到另一个状态时触发。应用规则与 onEnter 相同,在下一个状态上调用 transition() 或 handle() 将抛出异常。
onReset()
此方法用于在状态已转换且不再活动时清理状态。此方法用于从状态中移除事件绑定,因此如果您重写此方法,请确保调用父类的实现。
public function onReset() { // <-- Clean up logic here parent::onReset(); }
示例状态
use UnderStated\State; class StateOne extends State { /** * @param State * @return bool */ public function onEnter(State $previous) { $this->handle('myHandle'); return true; } /** * A state handler */ public function myHandle() { // I'm handled when the state changes } /** * @param State * @return boolean */ public function onExit(State $next) { // Will return true if unimplemented return true; } }
使用此状态时,只需将完全限定的类名作为构建器状态方法的第二个参数即可。
$builder->create() ->state('on', StateOne::class)
示例
请查看 示例,了解 FSM 可以以多种方式使用。
变更日志
0.0.4 -> 1.0.0
- 通用代码整理,遵守 PSR-2 规范,并删除了一些未使用的代码。
- 已弃用并移除
get方法,从MachineBuilder接口改为使用getMachine。 getMachine方法不接受任何参数,与它的前驱get不同,不能初始化一个状态机。Machine上的transition方法现在返回一个布尔值以指示成功。