PHP 有限状态机使用说明

php 有限状态机使用说明

winzou/state-machine

$config = array(
    'graph'         => 'myGraphA', // Name of the current graph - there can be many of them attached to the same object
    'property_path' => 'stateA',  // Property path of the object actually holding the state
    'states'        => array(
        'checkout',
        'pending',
        'confirmed',
        'cancelled'
    ),
    'transitions' => array(
        'create' => array(
            'from' => array('checkout'),
            'to'   => 'pending'
        ),
        'confirm' => array(
            'from' => array('checkout', 'pending'),
            'to'   => 'confirmed'
        ),
        'cancel' => array(
            'from' => array('confirmed'),
            'to'   => 'cancelled'
        )
    ),
    'callbacks' => array(
        'guard' => array(
            'guard-cancel' => array(
                'to' => array('cancelled'), // Will be called only for transitions going to this state
                'do' => function() { var_dump('guarding to cancelled state'); return false; }
            )
        ),
        'before' => array(
            'from-checkout' => array(
                'from' => array('checkout'), // Will be called only for transitions coming from this state
                'do'   => function() { var_dump('from checkout transition'); }
            )
        ),
        'after' => array(
            'on-confirm' => array(
                'on' => array('confirm'), // Will be called only on this transition
                'do' => function() { var_dump('on confirm transition'); }
            ),
            'to-cancelled' => array(
                'to' => array('cancelled'), // Will be called only for transitions going to this state
                'do' => function() { var_dump('to cancel transition'); }
            ),
            'cancel-date' => array(
                'to' => array('cancelled'),
                'do' => array('object', 'setCancelled'),
            ),
        )
    )
);

各个属性说明

1'property_path' => 'stateA'

需要在 DomainObject对象中定义,如:

class DomainObject
{
    private $stateA = 'checkout';//初始状态

    public function getStateA()
    {
        return $this->stateA;
    }
    public function setStateA($state)
    {
        $this->stateA = $state;
    }
}

2 states

定义所有可能的状态

'states' => array(
        'checkout',
        'pending',
        'confirmed',
        'cancelled'
    ),

3 transitions

定义了执行动作后的状态变化

'transitions' => array(
        'create' => array(
            'from' => array('checkout'),
            'to'   => 'pending'
        ),
        'confirm' => array(
            'from' => array('checkout', 'pending'),
            'to'   => 'confirmed'
        ),
        'cancel' => array(
            'from' => array('confirmed'),
            'to'   => 'cancelled'
        )
    ),

4 callbacks

定义了什么时候执行相对应的回调

'callbacks' => array(
        'guard' => array(
            'guard-cancel' => array(
                'to' => array('cancelled'), // Will be called only for transitions going to this state
                'do' => function() { var_dump('guarding to cancelled state'); return false; }
            )
        ),
        'before' => array(
            'from-checkout' => array(
                'from' => array('checkout'), // Will be called only for transitions coming from this state
                'do'   => function() { var_dump('from checkout transition'); }
            )
        ),
        'after' => array(
            'on-confirm' => array(
                'on' => array('confirm'), // Will be called only on this transition
                'do' => function() { var_dump('on confirm transition'); }
            ),
            'to-cancelled' => array(
                'to' => array('cancelled'), // Will be called only for transitions going to this state
                'do' => function() { var_dump('to cancel transition'); }
            ),
            'cancel-date' => array(
                'to' => array('cancelled'),
                'do' => array('object', 'setCancelled'),
            ),
        )
    )

下面这个定义了是否可以更改到当前状态,guard-cancel修饰作用没有实际意义,执行的时候会扫描整个数组,当to的指向状态是cancelled时执行do回调,当回调返回true的时候可以更改到该状态,类似于中间件

'guard' => array(
            'guard-cancel' => array(
                'to' => array('cancelled'), // Will be called only for transitions going to this state
                'do' => function() { var_dump('guarding to cancelled state'); return false; }
            )
        ),

通过guard之后会先执行before,数组的key其修饰作用,执行的时候会循环这个数组,当from的状态是checkout会执行do回调,

 'before' => array(
            'from-checkout' => array(
                'from' => array('checkout'), // Will be called only for transitions coming from this state
                'do'   => function() { var_dump('from checkout transition'); }
            )
        ),

before执行完之后,接下来开始扫描after数组,其key起装饰作用。有两种类型一种是on do,另一种是
to doon 对应的是transitions的key值,匹配到此key值就执行do回调。to对应的是要转换到的状态,匹配到此状态就执行do回调

 'after' => array(
            'on-confirm' => array(
                'on' => array('confirm'), // Will be called only on this transition
                'do' => function() { var_dump('on confirm transition'); }
            ),
            'to-cancelled' => array(
                'to' => array('cancelled'), // Will be called only for transitions going to this state
                'do' => function() { var_dump('to cancel transition'); }
            ),
            'cancel-date' => array(
                'to' => array('cancelled'),
                'do' => array('object', 'setCancelled'),
            ),
        )

do回调有两种方式一种是回调,另一种是DomainObject的方法

'do' => array('object', 'setCancelled'),

对应

class DomainObject
{
    private $stateA = 'checkout';//初始状态

    public function getStateA()
    {
        return $this->stateA;
    }
    public function setStateA($state)
    {
        $this->stateA = $state;
    }
     public function setConfirmedNow()
    {
        var_dump('I (the object) am set confirmed at '.date('Y-m-d').'.');
    }
}

setConfirmedNow方法


有三个事件

    const PRE_TRANSITION  = 'winzou.state_machine.pre_transition';
    const POST_TRANSITION = 'winzou.state_machine.post_transition';
    const TEST_TRANSITION = 'winzou.state_machine.test_transition';

可参考symfony/event-dispatcher

定义完图后,设置一个初始状态,例如把订单的checkout状态设置进去DomainObject中,然后操作执行相对应的方法(\$stateMachine->apply('create')),可能执行成功($stateMachine->getState(),设置状态进入订单表),也可能执行不成功(错误处理),

本作品采用《CC 协议》,转载必须注明作者和本文链接
Make everything simple instead of making difficulties as simple as possible
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
讨论数量: 4

看不懂你想表达的意思

6年前 评论
jcc123

@surest E-commerce 中订单系统的设计这篇文章的作者推荐的状态设计,github 上已有英文说明。阅读源码后,对各个属性进行了详细说明,做个记录

6年前 评论

怎么和laravel的模型结合使用,比如order模型有个state字段。

4年前 评论

acfun keke acc eg

  • acc

kakaxi

adsdf

kakaxi

bbq

code

ccccode

Uploading file...

Uploading file...

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!