PHPackages                             jagarsoft/php-state-machine - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. jagarsoft/php-state-machine

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

jagarsoft/php-state-machine
===========================

PHP StateMachine implementation

2.0.1(4y ago)5162[2 issues](https://github.com/jagarsoft/php-state-machine/issues)GPL-2.0-onlyPHPPHP ^7.4CI failing

Since Jul 29Pushed 4y ago1 watchersCompare

[ Source](https://github.com/jagarsoft/php-state-machine)[ Packagist](https://packagist.org/packages/jagarsoft/php-state-machine)[ RSS](/packages/jagarsoft-php-state-machine/feed)WikiDiscussions master Synced 6d ago

READMEChangelogDependencies (1)Versions (8)Used By (0)

PHP State Machine
=================

[](#php-state-machine)

 [![StateMachine Logo](https://github.com/jagarsoft/php-state-machine/raw/master/assets/images/StateMachine-Logo.png)](https://github.com/jagarsoft/php-state-machine/raw/master/assets/images/StateMachine-Logo.png)

 [![Scrutinizer Code Quality](https://camo.githubusercontent.com/001108a4c3d84d9bfbbd2425435c605349849fb304ae414ac899145170df4de6/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f6a61676172736f66742f7068702d73746174652d6d616368696e652f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/jagarsoft/php-state-machine/?branch=master) [![Code Coverage](https://camo.githubusercontent.com/d23b79ad72909906b1828090ec5ff074e521e091e3cbb8654d972feeb780c447/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f6a61676172736f66742f7068702d73746174652d6d616368696e652f6261646765732f636f7665726167652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/jagarsoft/php-state-machine/?branch=master) [![Build Status](https://camo.githubusercontent.com/d8134236aa0526a8d7bad540c1b7ca8da498300deb30e174b22fae8df687ce09/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f6a61676172736f66742f7068702d73746174652d6d616368696e652f6261646765732f6275696c642e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/jagarsoft/php-state-machine/build-status/master) [![Packagist Downloads](https://camo.githubusercontent.com/6043f77395cccaf910c59f7db9562e73d5fabdd5a90e2f82cf89bff670f4c517/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6a61676172736f66742f7068702d73746174652d6d616368696e653f7374796c653d706c6173746963)](https://packagist.org/packages/jagarsoft/php-state-machine) [![language PHP](https://camo.githubusercontent.com/fed4042cbfb45a4604a368cec9a62c6f928575af264c95ece069100a3fb45343/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c616e67756167652d5048502d677265656e2e7376673f6c6f6e6743616368653d74727565267374796c653d706c6173746963)](https://www.php.net/) [![GPL license](https://camo.githubusercontent.com/c62e5c0e3f49b16c064141370f0efdf9f896ce757b0585b3507e04920507c740/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d47504c2d626c75652e7376673f6c6f6e6743616368653d74727565267374796c653d706c6173746963)](http://perso.crans.org/besson/LICENSE.html) [![Badges shields.io](https://camo.githubusercontent.com/46e6b6401d91c05e39b5d03203f5008c95c52ee1b3c9cdd22470e73b8863d955/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6261646765732d736869656c64732e696f2d677265656e2e7376673f6c6f6e6743616368653d74727565267374796c653d706c6173746963)](https://shields.io)

What is a State Machine?
========================

[](#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](#user-content-fn-1-20d2638da1c9d158a0e6f34f2f4babbf):

[![State diagram for a turnstile](https://camo.githubusercontent.com/31d60acf3cd2d267dd7058a95628eb7d4e3017775a785e653331c7b41a42a924/68747470733a2f2f75706c6f61642e77696b696d656469612e6f72672f77696b6970656469612f636f6d6d6f6e732f7468756d622f392f39652f5475726e7374696c655f73746174655f6d616368696e655f636f6c6f7265642e7376672f33323070782d5475726e7374696c655f73746174655f6d616368696e655f636f6c6f7265642e7376672e706e67)](https://camo.githubusercontent.com/31d60acf3cd2d267dd7058a95628eb7d4e3017775a785e653331c7b41a42a924/68747470733a2f2f75706c6f61642e77696b696d656469612e6f72672f77696b6970656469612f636f6d6d6f6e732f7468756d622f392f39652f5475726e7374696c655f73746174655f6d616368696e655f636f6c6f7265642e7376672f33323070782d5475726e7374696c655f73746174655f6d616368696e655f636f6c6f7265642e7376672e706e67)

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](#user-content-fn-1-20d2638da1c9d158a0e6f34f2f4babbf):

[![state-transition-table](state-transition-table.png)](state-transition-table.png)

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
==========

[](#installing)

By *Composer*, just issue next command:

```
composer require jagarsoft/php-state-machine
```

Getting started
===============

[](#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
========

[](#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
=======

[](#licence)

GNU General Public License v2.0 only

Footnotes
---------

1. [https://en.wikipedia.org/wiki/Finite-state\_machine](https://en.wikipedia.org/wiki/Finite-state_machine) [↩](#user-content-fnref-1-20d2638da1c9d158a0e6f34f2f4babbf) [↩2](#user-content-fnref-1-2-20d2638da1c9d158a0e6f34f2f4babbf)

###  Health Score

25

—

LowBetter than 37% of packages

Maintenance12

Infrequent updates — may be unmaintained

Popularity12

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity56

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~35 days

Recently: every ~5 days

Total

7

Last Release

1539d ago

Major Versions

1.1.0 → 2.0.02022-02-26

PHP version history (2 changes)1.0.3PHP ^7.1

2.0.0PHP ^7.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/182835628ad769960900d3733457a633c8e033f4b1b29afa04dd95dca642c76d?d=identicon)[jagarsoft](/maintainers/jagarsoft)

---

Top Contributors

[![jagarsoft](https://avatars.githubusercontent.com/u/3843371?v=4)](https://github.com/jagarsoft "jagarsoft (36 commits)")

---

Tags

finite-state-machinefsmphpstate-machine

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/jagarsoft-php-state-machine/health.svg)

```
[![Health](https://phpackages.com/badges/jagarsoft-php-state-machine/health.svg)](https://phpackages.com/packages/jagarsoft-php-state-machine)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
