byjg/statemachine

创建简单的状态机

4.9.0 2023-05-21 22:46 UTC

This package is auto-updated.

Last update: 2024-09-16 05:33:49 UTC


README

Build Status Opensource ByJG GitHub source GitHub license GitHub release

该组件实现了有限状态机,可以定义多个状态并将它们分组在一系列转换(从一个状态到另一个状态)中。此外,每个状态都可以有一个条件,允许转移到另一个状态。

与其他状态机不同,此实现没有初始或最终状态。

基本示例

让我们使用以下示例。

我们有状态A、B、C和D,以及它们可能的转换。

首先,我们创建状态

$stA = new State("A");
$stB = new State("B");
$stC = new State("C");
$stD = new State("D");

然后,我们定义转换。请注意,每个转换对象都可以有一个接收混合类型 data 的闭包。此闭包需要返回 truefalse,允许或不允许转换。

$transitionA_B = new Transition($stA, $stB);
$transitionA_C = new Transition($stA, $stC);
$transitionB_D = new Transition($stB, $stD, function($data) {
    return !is_null($data);
});

在创建状态和转换之后,我们可以创建状态机

$stateMachine = FiniteStateMachine::createMachine()
    ->addTransition($transitionA_B)
    ->addTransition($transitionA_C)
    ->addTransition($transitionB_D);

我们可以使用 canTransition($from, $to) 方法验证转换。一些示例

$stateMachine->canTransition($stA, $stB);  // returns true
$stateMachine->canTransition($stA, $stC);  // returns true
$stateMachine->canTransition($stA, $stD);  // returns false
$stateMachine->canTransition($stB, $stA);  // returns false
$stateMachine->canTransition($stB, $stD);  // returns false
$stateMachine->canTransition($stB, $stD, ["some_info"]); // returns true
$stateMachine->canTransition($stC, $stD); //returns false

我们还可以检查状态是否为初始或最终状态

$stateMachine->isInitial($stA); // returns true
$stateMachine->isInitial($stB); // returns false
$stateMachine->isFinal($stA); // returns false
$stateMachine->isFinal($stC); // returns true
$stateMachine->isFinal($stD); // returns true

创建状态机的其他方法

或者,您可以使用以下参数使用 createMachine 工厂方法创建状态机

$stateMachine = FiniteStateMachine::createMachine(
    [
        ['A', 'B'],
        ['A', 'C'],
        ['B', 'D', function($data) {
            return !is_null($data);
        }]
    ]
);

使用自动转换

该组件的另一个特性是,根据您当前的状态以及传递给状态机的数据,它可以决定您可能进入的下一个状态。

让我们分析以下状态。

只有在满足某些条件的情况下,转换才可行。因此,让我们创建状态、可能的转换及其条件。

// States:
$stInitial = new State("__VOID__");
$stInStock = new State("IN_STOCK");
$stLastUnits = new State("LAST_UNITS");
$stOutOfStock = new State("OUT_OF_STOCK");

// Transitions:
$transitionInStock = Transition::create($stInitial, $stInStock, function ($data) {
    return $data["qty"] >= $data["min_stock"];
});

$transitionLastUnits = Transition::create($stInitial, $stLastUnits, function ($data) {
    return $data["qty"] > 0 && $data["qty"] < $data["min_stock"];
});

$transitionOutOfStock = Transition::create($stInitial, $stOutOfStock, function($data) {
    return $data["qty"] == 0;
});

// Create the Machine:
$stateMachine = FiniteStateMachine::createMachine()
    ->addTransition($transitionInStock)
    ->addTransition($transitionLastUnits)
    ->addTransition($transitionOutOfStock);

autoTransitionFrom 方法将检查是否可以使用实际数据执行转换以及转换到哪个状态。

$stateMachine->autoTransitionFrom($stInitial, ["qty" => 10, "min_stock" => 20])); // returns LAST_UNITS
$stateMachine->autoTransitionFrom($stInitial, ["qty" => 30, "min_stock" => 20])); // returns IN_STOCK
$stateMachine->autoTransitionFrom($stInitial, ["qty" => 00, "min_stock" => 20])); // returns OUT_OF_STOCK

自动转换后,返回的状态对象具有 ->getData(),其中包含用于验证的数据。

此外,您还可以使用闭包创建处理状态的转换。

例如。

$stN = new State('SOMESTATE', function ($data) {
    // execute some operation with the data
})

// After run and return $stN object
// We can do this:

$resultState = $stateMachine->autoTransitionFrom('STATE', [...  data ...]));
$resultState->process(); // This will run the closure defined with the data used to validate it.

其他方法

创建多个转换

$transitions = Transition::createMultiple([$from1, $from2], $to, $condition);

$machine = FiniteStateMachine::createMachine()
    ->addTransitions($transitions);

从特定状态获取可能的状态

$stateMachine->possibleTransitions($stA);

获取状态对象

// Return null if doesn't exist, otherwise return the object State
$state = $stateMachine->state('OUT_OF_STOCK');

安装

composer require "byjg/statemachine"

依赖关系

开源ByJG