PHPackages                             potfur/statemachine - 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. potfur/statemachine

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

potfur/statemachine
===================

State machine

2.0.0(10y ago)133211MITPHPPHP &gt;=5.4

Since Aug 2Pushed 9y ago4 watchersCompare

[ Source](https://github.com/potfur/statemachine)[ Packagist](https://packagist.org/packages/potfur/statemachine)[ RSS](/packages/potfur-statemachine/feed)WikiDiscussions dev Synced 1mo ago

READMEChangelog (2)Dependencies (3)Versions (4)Used By (1)

StateMachine
============

[](#statemachine)

[![Scrutinizer Code Quality](https://camo.githubusercontent.com/f5f5524a87fb3c1c4d53aa24389e63c092a65407aa4ea18596013f9ac28d52b1/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f706f746675722f73746174656d616368696e652f6261646765732f7175616c6974792d73636f72652e706e673f623d646576)](https://scrutinizer-ci.com/g/potfur/statemachine/?branch=dev)[![Code Coverage](https://camo.githubusercontent.com/a2360158a11ed88b4ef974bb408db7a17f936420c528e35e2f467807619a3f5f/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f706f746675722f73746174656d616368696e652f6261646765732f636f7665726167652e706e673f623d646576)](https://scrutinizer-ci.com/g/potfur/statemachine/?branch=dev)[![Build Status](https://camo.githubusercontent.com/83852ce32494f005eac6a4562fa76aca5cdb6a59d3f711e0fcf688abdaccfc4f/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f706f746675722f73746174656d616368696e652f6261646765732f6275696c642e706e673f623d646576)](https://scrutinizer-ci.com/g/potfur/statemachine/build-status/dev)[![License](https://camo.githubusercontent.com/e05324338e27eb9592dc676162460c5b8ae2ddc849526283026b195551a27a93/68747470733a2f2f706f7365722e707567782e6f72672f706f746675722f73746174656d616368696e652f6c6963656e73652e737667)](https://packagist.org/packages/potfur/statemachine)[![Latest Stable Version](https://camo.githubusercontent.com/318c16519137bd91755911d4e2eebd3ca445493e93df253e00a02e244f17b65d/68747470733a2f2f706f7365722e707567782e6f72672f706f746675722f73746174656d616368696e652f762f737461626c652e737667)](https://packagist.org/packages/potfur/statemachine)

StateMachine is an implementation of *state pattern*, also can be treated as *non-deterministic finite automata*. In different words - machine will react to events and move *conext* from one state to another depending on result of executed *command*.

StateMachine can be used to describe order &amp; payment processing, newsletter opt-in process, customer registration - any not trivial process.

Processes
---------

[](#processes)

StateMachine follows process defined by *states* taken by *context* and *events* that activate transitions between them.

Each of *events* can define two transitions *successful* and *erroneous*. Also, each *event* can have a callable command that will be executed before transition. Value returned by it, will decide which transition will be chosen.

When *command* returns `truthy` value - StateMachine will follow *successful* transitions, any `falsy` value will be *erroneous* transition. If *event* had no *command* - StateMachine will follow *successfull* transition.

Each *state* can have special event `StateMachine::ON_STATE_WAS_SET` which will be triggered as soon as *context* enters state.

Schema
------

[](#schema)

Processes are constructed from schemas. StateMachine comes with `ArrayFactory` which creates `Process` instances from plain arrays.

```
$commandResults = [
    true, // from new to pending
    false, // from pending to error (onStateWasSet)
    true, // from error to pending (onStateWasSet)
    true, // from pending to done (onStateWasSet)
];

$command = function () use (&$commandResults) {
    if (!count($commandResults)) {
        throw new \InvalidArgumentException('Out of results');
    }

    return array_shift($commandResults);
};

$schema = [
    'name' => 'testSchema',
    'initialState' => 'new',
    'states' => [
        [
            'name' => 'new',
            'events' => [
                [
                    'name' => 'goPending',
                    'targetState' => 'pending',
                    'errorState' => 'error',
                    'command' => $command,
                ]
            ],
        ],
        [
            'name' => 'pending',
            'events' => [
                [
                    'name' => StateMachine::ON_STATE_WAS_SET,
                    'targetState' => 'done',
                    'errorState' => 'error',
                    'command' => $command
                ]
            ],
        ],
        [
            'name' => 'error',
            'events' => [
                [
                    'name' => StateMachine::ON_STATE_WAS_SET,
                    'targetState' => 'pending',
                    'errorState' => 'error',
                    'command' => $command
                ]
            ],
        ],
        [
            'name' => 'done',
            'events' => [],
        ]
    ]
];

$process = (new ArrayFactory($schema))->getProcess();
```

Payload and triggering events
-----------------------------

[](#payload-and-triggering-events)

To transit from one state to another an event needs to be trigered. When it happens StateMachine will pass provided *context* wrapped as a payload to *command*, execute it and follow resulting transitions.

```
$payload = PayloadEnvelope::wrap('context');

$machine = new StateMachine($process);
$history = $machine->triggerEvent('goPending', $payload);
```

`PayloadEnvelope` is an implementation of `Payload` - simple wrapper that holds *context*. It can be anything, simple value, array, object etc. `::triggerEvent` method returns history of transitions, ie. list of all states that *context* passed.

###  Health Score

30

—

LowBetter than 64% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity15

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity60

Established project with proven stability

 Bus Factor1

Top contributor holds 98.7% 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 ~0 days

Total

2

Last Release

3942d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/8addaf28c1a25afd6006377779228ee980528e4ca23793a4ab8bc426dda5018b?d=identicon)[potfur](/maintainers/potfur)

---

Top Contributors

[![potfur](https://avatars.githubusercontent.com/u/1244857?v=4)](https://github.com/potfur "potfur (78 commits)")[![adampiotrowski](https://avatars.githubusercontent.com/u/6223254?v=4)](https://github.com/adampiotrowski "adampiotrowski (1 commits)")

###  Code Quality

TestsPHPUnit

Code StylePHP\_CodeSniffer

### Embed Badge

![Health badge](/badges/potfur-statemachine/health.svg)

```
[![Health](https://phpackages.com/badges/potfur-statemachine/health.svg)](https://phpackages.com/packages/potfur-statemachine)
```

###  Alternatives

[am-impact/amnav

Navigation Plugin for Craft

16726.5k](/packages/am-impact-amnav)[proteusthemes/wp-customizer-utilities

Advanced WordPress customizer controls and settings for better user experience.

329.4k1](/packages/proteusthemes-wp-customizer-utilities)[nightjar/ss-slug

Serve DataObjects as pages through an Action on a relation's Controller without referencing the ID

116.7k2](/packages/nightjar-ss-slug)

PHPackages © 2026

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