PHPackages                             dflydev/finite-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. dflydev/finite-state-machine

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

dflydev/finite-state-machine
============================

Yet another finite-state machine implementation

74.0k1[1 PRs](https://github.com/dflydev/dflydev-finite-state-machine/pulls)PHPCI failing

Since Apr 17Pushed 3mo agoCompare

[ Source](https://github.com/dflydev/dflydev-finite-state-machine)[ Packagist](https://packagist.org/packages/dflydev/finite-state-machine)[ RSS](/packages/dflydev-finite-state-machine/feed)WikiDiscussions master Synced 1w ago

READMEChangelogDependenciesVersions (3)Used By (0)

Finite-State Machine
====================

[](#finite-state-machine)

This library is yet another finite-state machine implementation.

[![Build Status](https://github.com/dflydev/dflydev-finite-state-machine/workflows/Build%20Status/badge.svg)](https://github.com/dflydev/dflydev-finite-state-machine/workflows/Build%20Status/badge.svg)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/b3398587e97b5eb5485030f54c907ec55654ba9f2bd25ca539b361658f020cd1/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f64666c796465762f64666c796465762d66696e6974652d73746174652d6d616368696e652f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/dflydev/dflydev-finite-state-machine/?branch=master)[![Code Coverage](https://camo.githubusercontent.com/bccce8df3ad9c53ee1ca78eeca29335d10146c9d71deb69d2b7baeeb266b918a/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f64666c796465762f64666c796465762d66696e6974652d73746174652d6d616368696e652f6261646765732f636f7665726167652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/dflydev/dflydev-finite-state-machine/?branch=master)[![Code Climate](https://camo.githubusercontent.com/803da6fcac13f0c1a0ea22d70a359ccee12d891dfca3253e6292b729ef5d9505/68747470733a2f2f636f6465636c696d6174652e636f6d2f6769746875622f64666c796465762f64666c796465762d66696e6974652d73746174652d6d616368696e652f6261646765732f6770612e737667)](https://codeclimate.com/github/dflydev/dflydev-finite-state-machine)

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

[](#installation)

```
composer require dflydev/finite-state-machine
```

Usage
-----

[](#usage)

Given the following definition for a domain class:

```
class DomainObject
{
    public string $state;
    public ?string $spy = null;

    public function __construct(string $state = 'new')
    {
        $this->state = $state;
    }
}
```

Given the following state definition for the "graphA" graph of our domain object:

```
$domainObjectGraphDefinition = [
   'class' => DomainObject::class,
   'graph' => 'graphA', // default is "default"
   'property_path' => 'state', // Configures `PropertyObjectProxy`
   'metadata' => [
       'title' => 'Graph A',
   ],
   'states' => [
       // a state as associative array
       ['name' => 'new'],
       // a state as associative array with metadata
       [
           'name' => 'pending_review',
           'metadata' => ['title' => 'Pending Review'],
       ],
       // states as string
       'awaiting_changes',
       'accepted',
       'published',
       'rejected',
   ],

   // list of all possible transitions
   'transitions' => [
       'create' => [
           'from' => ['new'],
           'to' => 'pending_review',
       ],
       'ask_for_changes' => [
           'from' =>  ['pending_review', 'accepted'],
           'to' => 'awaiting_changes',
           'metadata' => ['title' => 'Ask for changes'],
       ],
       'cancel_changes' => [
           'from' => ['awaiting_changes'],
           'to' => 'pending_review',
       ],
       'submit_changes' => [
           'from' => ['awaiting_changes'],
           'to' =>  'pending_review',
       ],
       'approve' => [
           'from' => ['pending_review', 'rejected'],
           'to' =>  'accepted',
       ],
       'publish' => [
           'from' => ['accepted'],
           'to' =>  'published',
       ],
   ],

   // list of all callbacks
   'callbacks' => [
       // will be called when testing a transition
       'guard' => [
           'guard_on_approving_from_rejected' => [
               // call the callback on a specific transition
               'on' => 'approve',
               'from' => 'rejected',
               // will call the method of this class
               'do' => function (
                   object $object,
                   Transition $transition,
                   State $fromState,
                   State $toState
               ) {
                   $object->spy = 'guard_on_approving_from_rejected';

                   // If a guard returns false, the transition will not happen
                   return false;
               },
               // arguments for the callback
               'args' => ['object'],
           ],
       ],

       // will be called before applying a transition
       'before' => [
           'spy-before-approve' => [
               'on' => 'ask_for_changes',
               'from' => 'accepted',
               'do' => function (
                   string $when,
                   object $object,
                   Transition $transition,
                   State $fromState,
                   State $toState
               ) {
                   Assert::equals($fromState->name(), $object->state);

                   $object->spy = $when . ' ask_for_changes from accepted';
               },
           ]
       ],

       // will be called after applying a transition
       'after' => [
           'spy-after-approve' => [
               'on' => 'ask_for_changes',
               'from' => 'accepted',
               'do' => function (
                   string $when,
                   object $object,
                   Transition $transition,
                   State $fromState,
                   State $toState
               ) {
                   Assert::equals($toState->name(), $object->state);
                   Assert::equals('before ask_for_changes from accepted', $object->spy);

                   $object->spy = $when . ' ask_for_changes from accepted';
               },
           ]
       ],
   ]
];
```

```
use Dflydev\FiniteStateMachine\FiniteStateMachineFactory;
use Dflydev\FiniteStateMachine\Graph\GraphResolver;
use Dflydev\FiniteStateMachine\Loader\WinzouArrayLoader;
use Dflydev\FiniteStateMachine\ObjectProxy\ObjectProxyResolver;
use Dflydev\FiniteStateMachine\ObjectProxy\PropertyObjectProxyFactory;

$graphResolver = new GraphResolver();
$objectProxyResolver = new ObjectProxyResolver();

// Add an object proxy that can directly read the state property from our objects
$objectProxyResolver->add(new PropertyObjectProxyFactory());

// Load a graph definition into our graph resolver
(new WinzouArrayLoader($graphResolver))->load($domainObjectGraphDefinition);

$finiteStateMachineFactory = new FiniteStateMachineFactory(
    $this->getGraphResolver(),
    $this->getObjectProxyResolver()
);

$finiteStateMachine = $finiteStateMachineFactory->build($object);

// "new"
$finiteStateMachine->currentState()->name();

// (bool) false
$finiteStateMachine->can('ask_for_changes');

// (bool) true
$finiteStateMachine->can('create');

$finiteStateMachine->apply('create');

// "pending_review"
$finiteStateMachine->currentState()->name();
```

Graph Definitions and Loaders
-----------------------------

[](#graph-definitions-and-loaders)

A graph is a named collection of states, transitions, and callbacks. An object may have multiple graphs defined.

The `GraphResolver` is responsible for resolving the graph definition for a given object (and optionally a graph name).

A `Graph` can be created manually and added to a `GraphResolver`. A `Loader` can be used to load a `Graph` into a `GraphResolver` based on specific types of resources.

### winzou/state-machine

[](#winzoustate-machine)

This library ships with `WinzouArrayLoader`, a `Loader` implementation that is loosely drop-in compatible with [winzou/state-machine](https://github.com/winzou/state-machine) array-based graph definitions.

### Custom

[](#custom)

This library ships with a `Loader` contract. Implementing this interface allows for the creation of custom graph definitions.

License
-------

[](#license)

MIT, see [LICENSE](LICENSE).

###  Health Score

32

—

LowBetter than 72% of packages

Maintenance53

Moderate activity, may be stable

Popularity23

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity37

Early-stage or recently created project

 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.

### Community

Maintainers

![](https://www.gravatar.com/avatar/0d6029bd16a0e8a9b97358a75b54affa6baadc1d9b0ca7eab2b6dd6c681ad7a8?d=identicon)[simensen](/maintainers/simensen)

---

Top Contributors

[![simensen](https://avatars.githubusercontent.com/u/191200?v=4)](https://github.com/simensen "simensen (8 commits)")

### Embed Badge

![Health badge](/badges/dflydev-finite-state-machine/health.svg)

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

###  Alternatives

[armincms/many-to-many

A Laravel Nova field.

2574.7k3](/packages/armincms-many-to-many)[mickey-kay/better-font-awesome-library

Better Font Awesome Library for WordPress

371.8k1](/packages/mickey-kay-better-font-awesome-library)

PHPackages © 2026

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