PHPackages                             daveawb/understated - 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. daveawb/understated

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

daveawb/understated
===================

A PHP Finite State Machine for Laravel 5+

0.0.4(9y ago)302.0k4MITPHP

Since Jun 1Pushed 7y ago1 watchersCompare

[ Source](https://github.com/Daveawb/UnderStated)[ Packagist](https://packagist.org/packages/daveawb/understated)[ RSS](/packages/daveawb-understated/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (4)Dependencies (7)Versions (5)Used By (0)

A PHP Finite State Machine (With Laravel 5.4 integration)
=========================================================

[](#a-php-finite-state-machine-with-laravel-54-integration)

[![Build Status](https://camo.githubusercontent.com/d3181acad4e88f6bc080bfabfa4682b5857c6bfc7928d2073869c8c9abd9982d/68747470733a2f2f7472617669732d63692e6f72672f446176656177622f556e6465725374617465642e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/Daveawb/UnderStated)

Why use an FSM?
---------------

[](#why-use-an-fsm)

FSM's allow developers tight control over the state of different resources within an application. There are many articles detailing FSM's and what they are and what they're capable of so I won't go into much detail here. Safe to say, by managing state within an FSM you centralise and manage state simply and cleanly without needing to build it into your business logic. There are plenty of examples within this repository that should give you an idea of the practical uses of an FSM. Some good examples are present in libraries such as Redux, Angular UI Router and Apollo. Whilst this is an implementation for PHP where state isn't as much of a problem as other languages or technologies (Browser based JS and more importantly NodeJS) a well constructed FSM can ease the burden of building and rationalising large scale applications.

Requirements
------------

[](#requirements)

- &gt;= PHP 7.0
- (optional) &gt;= Laravel 5.4

Installation
------------

[](#installation)

### Composer

[](#composer)

Add the following to your composer.json file

```
{
    "require": {
        "daveawb/understated": "0.0.4"
    }
}
```

### Laravel Integration

[](#laravel-integration)

Open `config/app.php` and register the required service provider.

```
'providers' => [
    // ...
    UnderStated\Providers\UnderStatedServiceProvider::class,
]
```

A Simple FSM
------------

[](#a-simple-fsm)

```
use UnderStated\States\State;

$builder = new UnderStated\Builders\GraphBuilder();

$fsm = $builder->create()

    // Create an 'on' state
    ->state('on', function() { /* state is on */ })

    // Create an 'off' state
    ->state('off', function() { /* state is off */ }, State::INITIAL)

    // Create a transition (undirected) between the two states
    ->transition('on', 'off', true)

    // Get the FSM instance
    ->get();
```

Now that we have that out of the way, how do you use it?

We declared an undirected transition between states 'on' and 'off'. This means that both those states are capable of transitioning from one to the other indefinitely. Also notice the `State::INITIAL` passed as the third argument to the 'off' state. This will mean that when the FSM is initialised this will be the state it is in.

Before we go any further we need to initialise the FSM.

```
// Initialise using the state marked with State::INITIAL or the first state added.
$fsm->initialise();

// If you want to override the initial state, pass it in to the `initialise` method
$fsm->initialise('on');
```

Now the FSM is initialised we can start transitioning from one state to another.

```
$fsm->transition('on');

echo ($fsm->getState()->getId()); // outputs 'on'

$fsm->transition('off');

echo ($fsm->getState()->getId()); // outputs 'off'
```

Class based FSM
---------------

[](#class-based-fsm)

Closures are useful for quick implementations but when complex behaviour is required within states and in the transition logic, it is much better to create state representations as classes. We'll look again at the on off example.

For full examples using states and implementing complex interactions please review the example implementations included in this project.

Each state has three predefined handles that are called automatically by the FSM. These are `onEnter()`, `onExit()` and `onReset()`.

### onEnter()

[](#onenter)

```
/**
 * Automatically called when this state is transitioned to. Returning false from
 * this method will block the transition attempt and the previous state will
 * remain as the active state.
 *
 * @param  State $previousState
 * @return boolean
 */
public function onEnter(State $previousState)
```

Calling `transition()` or `handle()` on the previous state however will throw an exception and will not fulfil either method.

### onExit()

[](#onexit)

```
/**
 * Automatically called when this state is transitioned from. Returning false from
 * this method will block the transition attempt and the current state will
 * remain as the active state.
 *
 * @param  State $nextState
 * @return boolean
 */
public function onExit(State $nextState)
```

This method, much like onEnter, is fired when transitioning from the current state to another. The same rules apply as per onEnter, calling `transition()` or `handle()` on the next state will throw an exception.

### onReset()

[](#onreset)

This method is used for cleaning up the state once it has been transitioned from and is no longer active. This method is used internally for removing event bindings from the state and as such if you override this method be sure to call the parents implementation.

```
public function onReset()
{
    // handle('myHandle');

        return true;
    }

    /**
     * A state handler
     */
    public function myHandle()
    {
        // I'm handled when the state changes
    }

    /**
     * @param State
     * @return boolean
     */
    public function onExit(State $next)
    {
        // Will return true if unimplemented
        return true;
    }
}
```

Using this state is a case of giving the fully qualified class name as the second parameter to the builders state method.

```
$builder->create()
    ->state('on', StateOne::class)
```

Examples
========

[](#examples)

Take a look at the [examples](https://github.com/Daveawb/UnderStated/tree/master/examples) for a comprehensive select of different ways the FSM can be used.

Changelog
=========

[](#changelog)

0.0.4 -&gt; 1.0.0

- General code tidy up, PSR-2 compliance and removed some unused code.
- Deprecated and removed `get` method from the `MachineBuilder` interface in favour of `getMachine`.
- `getMachine` method accepts no arguments and can not initialise an FSM unlike its precursor `get`.
- `transition` method on `Machine` now returns a boolean to indicate success.

###  Health Score

32

—

LowBetter than 70% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity27

Limited adoption so far

Community15

Small or concentrated contributor base

Maturity56

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 82.6% 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 ~222 days

Total

4

Last Release

3358d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/4da1dd512c9c67b9df1daaee868bb67e9a1330b66da3232269fd54baa4a0b35a?d=identicon)[daveawb](/maintainers/daveawb)

---

Top Contributors

[![Daveawb](https://avatars.githubusercontent.com/u/4409005?v=4)](https://github.com/Daveawb "Daveawb (38 commits)")[![syhol](https://avatars.githubusercontent.com/u/642428?v=4)](https://github.com/syhol "syhol (3 commits)")[![vidorge](https://avatars.githubusercontent.com/u/989725?v=4)](https://github.com/vidorge "vidorge (3 commits)")[![dodocinho](https://avatars.githubusercontent.com/u/192278?v=4)](https://github.com/dodocinho "dodocinho (1 commits)")[![edouardpoitras](https://avatars.githubusercontent.com/u/14075649?v=4)](https://github.com/edouardpoitras "edouardpoitras (1 commits)")

---

Tags

laravelfsmstates

###  Code Quality

TestsBehat

### Embed Badge

![Health badge](/badges/daveawb-understated/health.svg)

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

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3325.1M337](/packages/psalm-plugin-laravel)[mongodb/laravel-mongodb

A MongoDB based Eloquent model and Query builder for Laravel

7.1k8.0M84](/packages/mongodb-laravel-mongodb)[laravel/ai

The official AI SDK for Laravel.

9782.1M153](/packages/laravel-ai)[illuminate/view

The Illuminate View package.

13046.3M2.1k](/packages/illuminate-view)[chelout/laravel-relationship-events

Missing relationship events for Laravel

5232.4M17](/packages/chelout-laravel-relationship-events)[pressbooks/pressbooks

Pressbooks is an open source book publishing tool built on a WordPress multisite platform. Pressbooks outputs books in multiple formats, including PDF, EPUB, web, and a variety of XML flavours, using a theming/templating system, driven by CSS.

45344.0k1](/packages/pressbooks-pressbooks)

PHPackages © 2026

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