Skip to content

jagarsoft/php-state-machine

Repository files navigation

PHP State Machine

StateMachine Logo

Scrutinizer Code Quality Code Coverage Build Status Packagist Downloads language PHP GPL license Badges shields.io

What is a State Machine?

It's a data structure made of two key items:

  • States
  • Transitions

Transitions go from an initial state to a destination state fired by events.

You can view a State Machine as a graph like this 1:

State diagram for a turnstile

Also, you can think about it, as a double-entry array or State Transition Table indexed by current state and current event. Content will be the next state 1:

state-transition-table

Bound to the next state, you can set a action function that will be executed when event will be raised at the current state, after run, the new state will be set. In foremention example, output may be the action performed by bound function over some servomotor or something like that (save data, etc).

You can cancel the transition to the next state invoking cancelTransition within action function. Current state will be remain.

Action functions are atomic. If you fire new events in an action function, they will be enqueued, and their action functions, if any, will be invoked consecutively, every time action function return.

If you cancel transition within a nested event, subsequent events may fail if no alternative event is defined for the current state.

Unexpected events for the current state will throw an exception.

You can fire common event from any state, by defining a addCommonTransition with expected event and destination state only, but you must add all states yet.

Installing

By Composer, just issue next command:

composer require jagarsoft/php-state-machine

Getting started

$state_1 = StateEnum::STATE_1;
$state_2 = StateEnum::STATE_2;
$state_3 = StateEnum::STATE_3;

$event_a = EventEnum::EVENT_A;
$event_b = EventEnum::EVENT_B;
$event_c = EventEnum::EVENT_C;

echo PHP_EOL;
$commonAction = function (StateMachine $sm){
    echo "My current state is {$sm->getCurrentState()}".
         " on {$sm->getCurrentEvent()}".
         " and {$sm->getNextState()} will be the next state".PHP_EOL;
};

(new StateMachine())
        ->addState($state_1)
        ->addState($state_2)
        ->addState($state_3)

        ->addTransition($state_1, $event_a, $state_2, $commonAction)
        ->addTransition($state_2, $event_b, $state_3, $commonAction)
        ->addTransition($state_3, $event_c, $state_1, $commonAction)

        ->fireEvent($event_a)
        ->fireEvent($event_b)
        ->fireEvent($event_c)

        ->fireEvent($event_a)
        ->fireEvent($event_b)
        ->fireEvent($event_c);

Output:

My current state is 1 on A and 2 will be the next state
My current state is 2 on B and 3 will be the next state
My current state is 3 on C and 1 will be the next state
My current state is 1 on A and 2 will be the next state
My current state is 2 on B and 3 will be the next state
My current state is 3 on C and 1 will be the next state

Features

StateMachine gives you the followings features:

  1. You can prove a event before it be fired
  2. You can execute a guard in order to cancel transition
  3. You can execute a function before and/or after action
  4. You can create StateMachine from Array or Winzou config
  5. You can store extra data in transition

Coming soon... you will be able to create StateMachine from other sources, for instance, DOT definition. StateMachine so created is fully functional and will respond to their events. Moveover, you will be able to save your current StateMachine to that format too.

Licence

GNU General Public License v2.0 only

Footnotes

  1. https://en.wikipedia.org/wiki/Finite-state_machine 2