daveawb/understated

Laravel 5+ 的 PHP 有限状态机

0.0.4 2017-03-30 09:11 UTC

This package is not auto-updated.

Last update: 2024-09-14 17:37:30 UTC


README

Build Status

为什么使用 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 方法现在返回一个布尔值以指示成功。