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

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

byjg/statemachine
=================

Finite State Machine implementation with conditional transitions and state actions

6.0.0(7mo ago)29.8k↓20.5%MITPHPPHP &gt;=8.3 &lt;8.6CI failing

Since Oct 12Pushed 3mo ago1 watchersCompare

[ Source](https://github.com/byjg/php-statemachine)[ Packagist](https://packagist.org/packages/byjg/statemachine)[ GitHub Sponsors](https://github.com/byjg)[ RSS](/packages/byjg-statemachine/feed)WikiDiscussions master Synced 2d ago

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

   sidebar\_key statemachine   tags    php

    State Machine
=============

[](#state-machine)

This component implements a Finite State Machine, which can define several states and group them in a collection of transitions (from one state to another state). In addition, each state can have a conditional allowing move to another state.

[![Sponsor](https://camo.githubusercontent.com/fab14b7f7f475072ada0473f193d6f322561fd4a2958e0cc89910d053347cf27/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f53706f6e736f722d2532336561346161613f6c6f676f3d67697468756273706f6e736f7273266c6f676f436f6c6f723d7768697465266c6162656c436f6c6f723d306431313137)](https://github.com/sponsors/byjg)[![Build Status](https://github.com/byjg/php-statemachine/actions/workflows/phpunit.yml/badge.svg?branch=master)](https://github.com/byjg/php-statemachine/actions/workflows/phpunit.yml)[![Opensource ByJG](https://camo.githubusercontent.com/425c1bbccc0f292bf4d20569ae74a6b2e384fd648f1af8911bc61de9a8dcfc0b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6f70656e736f757263652d62796a672d737563636573732e737667)](http://opensource.byjg.com)[![GitHub source](https://camo.githubusercontent.com/88e61eb211719144efdd570290a0456b6e13099c2df8d973f1bb43fe33bf0039/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4769746875622d736f757263652d696e666f726d6174696f6e616c3f6c6f676f3d676974687562)](https://github.com/byjg/php-statemachine/)[![GitHub license](https://camo.githubusercontent.com/1fc4da084a6e48832c27058f25031057b8d866833f0759c80bc835e52f88b0de/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f62796a672f7068702d73746174656d616368696e652e737667)](https://opensource.byjg.com/opensource/licensing.html)[![GitHub release](https://camo.githubusercontent.com/2485f9a355f6d832951e005861653103f0097a49a10fcbcc6b9bf3e75091e96d/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f72656c656173652f62796a672f7068702d73746174656d616368696e652e737667)](https://github.com/byjg/php-statemachine/releases/)

Differently from other State machines, this implementation doesn't have an initial or final state.

Documentation
-------------

[](#documentation)

- [Basic Usage](docs/basic-usage.md)
- [Auto Transition](docs/auto-transition.md)
- [Error Handling](docs/error-handling.md)
- [Advanced Features](docs/advanced-features.md)

Basic Example
-------------

[](#basic-example)

Let's use the following example.

 ```
flowchart LR
    A[State A] --> B[State B]
    A --> C[State C]
    B -- Some Event --> D[State D]
```

      Loading We have the states A, B, C, and D, and it's their possible transitions.

First, we create the states:

```
$stA = new State("A");
$stB = new State("B");
$stC = new State("C");
$stD = new State("D");
```

Then, we define the transitions. Each transition can optionally have a condition that implements `TransitionConditionInterface`. The `canTransition()` method receives the `data` array and returns `true` or `false` to allow or deny the transition.

```
use ByJG\StateMachine\TransitionConditionInterface;

$transitionA_B = new Transition($stA, $stB);
$transitionA_C = new Transition($stA, $stC);

$condition = new class implements TransitionConditionInterface {
    public function canTransition(?array $data): bool {
        return !is_null($data);
    }
};
$transitionB_D = new Transition($stB, $stD, $condition);
```

After creating the states and the transition, we can create the State Machine:

```
$stateMachine = FiniteStateMachine::createMachine()
    ->addTransition($transitionA_B)
    ->addTransition($transitionA_C)
    ->addTransition($transitionB_D);
```

We can validate the transition using the method `canTransition($from, $to)`. Some examples:

```
$stateMachine->canTransition($stA, $stB);  // returns true
$stateMachine->canTransition($stA, $stC);  // returns true
$stateMachine->canTransition($stA, $stD);  // returns false
$stateMachine->canTransition($stB, $stA);  // returns false
$stateMachine->canTransition($stB, $stD);  // returns false
$stateMachine->canTransition($stB, $stD, ["some_info"]); // returns true
$stateMachine->canTransition($stC, $stD); //returns false
```

We can also check if a state is initial or final:

```
$stateMachine->isInitialState($stA); // returns true
$stateMachine->isInitialState($stB); // returns false
$stateMachine->isFinalState($stA); // returns false
$stateMachine->isFinalState($stC); // returns true
$stateMachine->isFinalState($stD); // returns true
```

### Other ways to create the State Machine

[](#other-ways-to-create-the-state-machine)

Alternatively, you can create the state machine using the `createMachine` factory method with arguments as follows:

```
$condition = new class implements TransitionConditionInterface {
    public function canTransition(?array $data): bool {
        return !is_null($data);
    }
};

$stateMachine = FiniteStateMachine::createMachine(
    [
        ['A', 'B'],
        ['A', 'C'],
        ['B', 'D', $condition]
    ]
);
```

Using the Auto Transition
-------------------------

[](#using-the-auto-transition)

Another feature of this component is that depending on the state you are in and the data you pass to the state machine, it can decide what is the next state you can be.

Let's analyze the following states.

 ```
flowchart LR
    .[Initial State] -- qty == 0 --> A[Out of stock]
    . -- 0 < qty < min_stock --> B[Last Units]
    . -- qty >= min_stock --> C[In Stock]
```

      Loading The transition is only possible if some conditions are satisfied. So, let's create the state, the possible transitions and its conditions.

```
use ByJG\StateMachine\TransitionConditionInterface;

// States:
$stInitial = new State("__VOID__");
$stInStock = new State("IN_STOCK");
$stLastUnits = new State("LAST_UNITS");
$stOutOfStock = new State("OUT_OF_STOCK");

// Transition conditions:
$inStockCondition = new class implements TransitionConditionInterface {
    public function canTransition(?array $data): bool {
        return $data["qty"] >= $data["min_stock"];
    }
};

$lastUnitsCondition = new class implements TransitionConditionInterface {
    public function canTransition(?array $data): bool {
        return $data["qty"] > 0 && $data["qty"] < $data["min_stock"];
    }
};

$outOfStockCondition = new class implements TransitionConditionInterface {
    public function canTransition(?array $data): bool {
        return $data["qty"] == 0;
    }
};

// Transitions:
$transitionInStock = Transition::create($stInitial, $stInStock, $inStockCondition);
$transitionLastUnits = Transition::create($stInitial, $stLastUnits, $lastUnitsCondition);
$transitionOutOfStock = Transition::create($stInitial, $stOutOfStock, $outOfStockCondition);

// Create the Machine:
$stateMachine = FiniteStateMachine::createMachine()
    ->addTransition($transitionInStock)
    ->addTransition($transitionLastUnits)
    ->addTransition($transitionOutOfStock);
```

The method `autoTransitionFrom` will check if is possible to do the transition with the actual data and to what state.

```
$stateMachine->autoTransitionFrom($stInitial, ["qty" => 10, "min_stock" => 20]); // returns LAST_UNITS
$stateMachine->autoTransitionFrom($stInitial, ["qty" => 30, "min_stock" => 20]); // returns IN_STOCK
$stateMachine->autoTransitionFrom($stInitial, ["qty" => 0, "min_stock" => 20]); // returns OUT_OF_STOCK
```

When auto transitioned, the state object returned has the `->getData()` method with the data used to validate it.

### Processing State with Actions

[](#processing-state-with-actions)

You can also create a state with an action that will execute when the state is reached.

e.g.

```
use ByJG\StateMachine\StateActionInterface;

$action = new class implements StateActionInterface {
    public function execute(?array $data): void {
        // Execute some operation with the data
        // This is the STATE action, not the transition condition
        echo "Processing state with: " . json_encode($data);
    }
};

$stN = new State('SOMESTATE', $action);

// After autoTransition returns the $stN state object
// You can execute its action:

$resultState = $stateMachine->autoTransitionFrom('STATE', [... data ...]);
$resultState->process(); // This will run the state's action with the data
```

**Note:** The `TransitionConditionInterface` validates transitions (returns true/false to allow/deny). The `StateActionInterface` executes actions when the state is processed.

Other Methods
-------------

[](#other-methods)

### Create multiple transitions

[](#create-multiple-transitions)

```
$condition = new class implements TransitionConditionInterface {
    public function canTransition(?array $data): bool {
        return isset($data["approved"]) && $data["approved"] === true;
    }
};

$transitions = Transition::createMultiple([$from1, $from2], $to, $condition);

$machine = FiniteStateMachine::createMachine()
    ->addTransitions($transitions);
```

### Get possible states from a specific state

[](#get-possible-states-from-a-specific-state)

```
$stateMachine->possibleTransitions($stA);
```

### Get the State object

[](#get-the-state-object)

```
// Return null if doesn't exist, otherwise return the object State
$state = $stateMachine->state('OUT_OF_STOCK');
```

Install
-------

[](#install)

```
composer require "byjg/statemachine"
```

Dependencies
------------

[](#dependencies)

 ```
flowchart TD
    byjg/statemachine
```

      Loading ---

[Open source ByJG](http://opensource.byjg.com)

###  Health Score

48

—

FairBetter than 93% of packages

Maintenance72

Regular maintenance activity

Popularity27

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity69

Established project with proven stability

 Bus Factor1

Top contributor holds 91.2% 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 ~227 days

Total

6

Last Release

223d ago

Major Versions

1.0.0 → 4.9.02023-05-21

4.9.0 → 5.0.x-dev2024-10-27

5.0.0 → 6.0.02025-11-22

PHP version history (2 changes)5.0.x-devPHP &gt;=8.1 &lt;8.4

6.0.0PHP &gt;=8.3 &lt;8.6

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/981924?v=4)[Joao Gilberto Magalhaes](/maintainers/byjg)[@byjg](https://github.com/byjg)

---

Top Contributors

[![byjg](https://avatars.githubusercontent.com/u/981924?v=4)](https://github.com/byjg "byjg (31 commits)")[![claude](https://avatars.githubusercontent.com/u/81847?v=4)](https://github.com/claude "claude (3 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Type Coverage Yes

### Embed Badge

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

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

###  Alternatives

[stackkit/laravel-google-cloud-scheduler

33266.0k](/packages/stackkit-laravel-google-cloud-scheduler)

PHPackages © 2026

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