PHP 有限狀態機使用說明

jcc123發表於2019-04-19

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 協議》,轉載必須註明作者和本文連結
NOT IS BECAUSE I WANT TO WRITE, BUT I WANT TO INCREASE, SO I GO TO WRITE~~

相關文章