potfur/statemachine

2.0.0 2015-08-02 09:25 UTC

This package is not auto-updated.

Last update: 2024-09-14 17:05:23 UTC


README

Scrutinizer Code Quality Code Coverage Build Status License Latest Stable Version

状态机是实现 状态模式 的实现,也可以被视为 非确定性有限自动机。换句话说——机器会根据执行的 命令 结果对事件做出反应,并将 上下文 从一个状态移动到另一个状态。

状态机可以用来描述订单与支付处理、新闻通讯订阅过程、客户注册等任何非简单过程。

流程

状态机遵循由 状态事件 定义的流程,状态上下文 所采取的,事件 激活了它们之间的转换。

每个 事件 可以定义两个转换 成功的错误的。此外,每个 事件 都可以有一个可调用的命令,该命令在转换之前执行。由它返回的值将决定选择哪个转换。

命令 返回 真值 时,状态机将遵循 成功的 转换,任何 假值 都将是 错误的 转换。如果 事件 没有定义 命令,状态机将遵循 成功的 转换。

每个 状态 都可以有一个特殊的事件 StateMachine::ON_STATE_WAS_SET,一旦 上下文 进入状态,它就会触发。

模式

流程是由模式构建的。状态机附带 ArrayFactory,它可以从平面数组创建 Process 实例。

$commandResults = [
    true, // from new to pending
    false, // from pending to error (onStateWasSet)
    true, // from error to pending (onStateWasSet)
    true, // from pending to done (onStateWasSet)
];

$command = function () use (&$commandResults) {
    if (!count($commandResults)) {
        throw new \InvalidArgumentException('Out of results');
    }

    return array_shift($commandResults);
};

$schema = [
    'name' => 'testSchema',
    'initialState' => 'new',
    'states' => [
        [
            'name' => 'new',
            'events' => [
                [
                    'name' => 'goPending',
                    'targetState' => 'pending',
                    'errorState' => 'error',
                    'command' => $command,
                ]
            ],
        ],
        [
            'name' => 'pending',
            'events' => [
                [
                    'name' => StateMachine::ON_STATE_WAS_SET,
                    'targetState' => 'done',
                    'errorState' => 'error',
                    'command' => $command
                ]
            ],
        ],
        [
            'name' => 'error',
            'events' => [
                [
                    'name' => StateMachine::ON_STATE_WAS_SET,
                    'targetState' => 'pending',
                    'errorState' => 'error',
                    'command' => $command
                ]
            ],
        ],
        [
            'name' => 'done',
            'events' => [],
        ]
    ]
];

$process = (new ArrayFactory($schema))->getProcess();

有效载荷和触发事件

要从一种状态转换到另一种状态,需要触发一个事件。当发生这种情况时,状态机会将提供的 上下文 包装为有效载荷传递给 命令,执行它并遵循结果的转换。

$payload = PayloadEnvelope::wrap('context');

$machine = new StateMachine($process);
$history = $machine->triggerEvent('goPending', $payload);

PayloadEnvelopePayload 的实现——一个简单的包装器,用于持有 上下文。它可以是一切,简单的值、数组、对象等。`::triggerEvent` 方法返回转换历史,即上下文通过的所有状态的列表。