Finite-state machine allows you to create an object, containing different states and transitions between them, that can change its behaivour according to the current state.
For installing the FSM machine use Composer. Simply add following to your composer.json file:
"require": {
"zinovyev/php-fsm": "0.6.5"
}- Create State classes and define states:
class StateA extends State
{
publicfunctionfoo($name)
{
printf("Hello, %s!", $name);
}
}- Create a new FSM\Client instance (StateMachine).
- Bind your States to the Client instance, apply transactions and set initial state:
class StateMachine extends Client
{
publicfunction __construct()
{
parent::__construct();
/* ... */$this
->addState($stateA)
/* ... */
->createTransition('fourth', 'stateA', 'stateB')
/* ... */or
$stateMachine = newClient;
$stateMachine
->addState($stateA)
->addState($stateB)
->createTransition('fourth', 'stateA', 'stateB')
;- Use Memento if you want do store current State and parameters and restore them later:
$memento = $stateMachine->createMemento();and restore:
$stateMachine = newStateMachine();
$stateMachine->applyMemento($memento);- That's all =) Your simple State machine is now configured and ready for use!
<?phprequire_once('vendor/autoload.php');
useFSM\Client;
useFSM\State\State;
useFSM\State\StateInterface;
/** * StateA class */class StateA extends State
{
publicfunctionfoo($f)
{
return$f;
}
}
/** * StateB class */class StateB extends State
{
publicfunctionbar($b)
{
return$b * 2;
}
}
/** * StateC class */class StateC extends State
{
publicfunctionfooBar($fb)
{
returnstrrev($fb);
}
publicfunctionshuffle(array$array) {
shuffle($array);
return$array;
}
}
/** * StateMachine example class */class StateMachine extends Client
{
publicfunction__construct()
{
parent::__construct();
// Create StateA initial type instance of class StateA$stateA = newStateA();
$stateA->setName('stateA');
$stateA->setType(StateInterface::TYPE_INITIAL);
// Create StateB finite type instance of class StateB$stateB = newStateB();
$stateB->setName('stateB');
$stateB->setType(StateInterface::TYPE_FINITE);
// Create StateC regular type instance of class StateC$stateC = newStateC();
$stateC->setName('stateC');
$stateC->setType(StateInterface::TYPE_REGULAR);
// Create StateD regular type instance of class StateB$stateD = newStateB();
$stateD->setName('stateD');
$stateD->setType(StateInterface::TYPE_REGULAR); // Attach states and transitions$this
->addState($stateA)
->addState($stateB)
->addState($stateC)
->addState($stateD)
->setInitialState($stateA)
->createTransition('initial', 'stateA', 'stateA')
->createTransition('second', 'stateA', 'stateC')
->createTransition('secondAlternative', 'stateA', 'stateD')
->createTransition('third', 'stateC', 'stateD')
->createTransition('thirdAlternative', 'stateD', 'stateC')
->createTransition('fourth', 'stateD', 'stateB')
->createTransition('fourthAlternative', 'stateC', 'stateB')
->createTransition('shortWay', 'stateA', 'stateB')
;
}
}
// Create new StateMachine instance$stateMachine = newStateMachine();
$stateMachine->foo = 'bar'; // Add public property// Test StateA stateprintf("%d) State machine is at state: '%s'. Test function call result is: '%s'\n", 1,
$stateMachine->getCurrentState()->getName(), // Get State Name$stateMachine->callAction('foo', $properties = [100]) // Call State function
);
// Accept transition "initial"$stateMachine->acceptTransitionByName('initial');
printf("%d) State machine is at SAME state: '%s'. Test function call result: '%s'\n", 2,
$stateMachine->getCurrentState()->getName(), // Get State Name$stateMachine->callAction('foo', $properties = [200]) // Call State function
);
// Accept transition "second"$stateMachine->acceptTransitionByName('second');
printf("%d) State machine is at state: '%s'. Test function call result: '%s'\n", 3,
$stateMachine->getCurrentState()->getName(), // Get State Name$stateMachine->fooBar('foo bar') // Call State function
);
// Create a memento (snapshot) of the current state$memento = $stateMachine->createMemento();
// Unset StateMachine$stateMachine = null;
unset($stateMachine);
// Restore StateMachine from a snapshot (Memento)$stateMachine = newStateMachine();
$stateMachine->applyMemento($memento);
printf("=*= Check property value after restore: \$foo='%s' =*=\n", $stateMachine->foo);
// Accept transition "third"$stateMachine->acceptTransitionByName('third');
printf("%d) State machine is at state '%s'. Test function call result: '%s'\n", 4,
$stateMachine->getCurrentState()->getName(), // Get State Name$stateMachine->bar(1) // Call State function
);
// Accept transition "fourth"$stateMachine->acceptTransitionByName('fourth');
printf("%d) State machine is at state '%s'. Test function call result: '%s'\n", 5,
$stateMachine->getCurrentState()->getName(), // Get State Name$stateMachine->bar(2) // Call State function
);If you run the code in your console, you'll see the following output:
1) State machine is at state: 'stateA'. Test function call result is: '100'
2) State machine is at SAME state: 'stateA'. Test function call result: '200'
3) State machine is at state: 'stateC'. Test function call result: 'rab oof'
=*= Check property value after restore: $foo='bar' =*=
4) State machine is at state 'stateD'. Test function call result: '2'
5) State machine is at state 'stateB'. Test function call result: '4'