PHPackages                             ironbound/state - 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. ironbound/state

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

ironbound/state
===============

IronBound State Machine Library

0.5(6y ago)1351[1 PRs](https://github.com/iron-bound-designs/IronBound-State/pulls)MITPHPPHP ^7.2CI failing

Since Dec 28Pushed 3mo ago2 watchersCompare

[ Source](https://github.com/iron-bound-designs/IronBound-State)[ Packagist](https://packagist.org/packages/ironbound/state)[ RSS](/packages/ironbound-state/feed)WikiDiscussions master Synced 5d ago

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

IronBound State
===============

[](#ironbound-state)

[![Build Status](https://camo.githubusercontent.com/cdcb835d16fd79660686c055405fe6f4e347d9e9044d7581abb039816024d24b/68747470733a2f2f7472617669732d63692e636f6d2f69726f6e2d626f756e642d64657369676e732f49726f6e426f756e642d53746174652e7376673f6272616e63683d6d6173746572)](https://travis-ci.com/iron-bound-designs/IronBound-State) [![codecov](https://camo.githubusercontent.com/3a750c40ef9dbf62d8b64234b85e6d517e7a4c639b8d577ae3852167ccc1c7c3/68747470733a2f2f636f6465636f762e696f2f67682f69726f6e2d626f756e642d64657369676e732f49726f6e426f756e642d53746174652f6272616e63682f6d61737465722f67726170682f62616467652e737667)](https://codecov.io/gh/iron-bound-designs/IronBound-State) [![Latest Stable Version](https://camo.githubusercontent.com/812d2c4346f9e87ea8cd602d75e3c109859401ed38202ed560f755d307753f13/68747470733a2f2f706f7365722e707567782e6f72672f69726f6e626f756e642f73746174652f762f737461626c65)](https://packagist.org/packages/ironbound/state) [![License](https://camo.githubusercontent.com/8700cea608fc0c49114d3dbb173bcb47a7ae41d6f3e5a711094c7aef4f7cafd4/68747470733a2f2f706f7365722e707567782e6f72672f69726f6e626f756e642f73746174652f6c6963656e7365)](https://packagist.org/packages/ironbound/state)

IronBound State is a State Machine library heavily influenced by `yohang/finite`.

Usage
-----

[](#usage)

```
use IronBound\State\Factory\StateMachineFactory;
use IronBound\State\Graph\GraphId;
use IronBound\State\Transition\TransitionId;

/** @var StateMachineFactory $stateMachineFactory */
$subject = new Order();
$machine = $stateMachineFactory->make($subject, new GraphId('payment'));
$state   = $machine->getCurrentState(); // State object for "unpaid"

$machine->apply(new TransitionId('pay'));
echo $subject->paymentStatus; // processing

foreach ($machine->getAvailableTransitions() as $transition) {
    echo $transition->getId();
}

if ($machine->evaluate(new TransitionId('refund'))->isValid()) {
    // do refund.
}
```

Core Components
---------------

[](#core-components)

### Subject

[](#subject)

The subject is the object that maintains state and has transitions applied to it. The only requirement is that it is a PHP object; there is no `interface` defined for subjects.

### State

[](#state)

The `State` object represents the current state the subject is in. For instance, a post could be in the "Pending" state or "Published" state. A delivery state could be "Processing", "Waiting at Carrier", "In Transit", and "Delivered".

### Transition

[](#transition)

The `Transition` object defines how a subject moves from one state to another. For instance, when you "Publish" a post it moves from the "Pending" state to the "Published" state. When you "Deliver to Carrier" a package, it transitions from "Processing" to "Waiting at Carrier".

### Graph

[](#graph)

The `Graph` object is responsible for holding the set of available states a subject can be in and the list of transitions between those states.

A subject can have more than one Graph. For instance, an ecommerce order might have a payment status and a delivery status. Each status is a separate graph.

### State Machine

[](#state-machine)

The `StateMachine` is how you interact with a subject's state and transition between states. It can tell you what transitions are available from the current state and apply a transition to change the subject's state.

### State Mediator

[](#state-mediator)

There are many different ways that a subject can store and change it's state. For instance, it could be an instance property, behind a method, or perhaps tracked somewhere completely separate from the subject's data. The `StateMediator` is used to abstract these details away from the `StateMachine`.

Factories
---------

[](#factories)

The most direct way to use IronBound State is to instantiate a `ConcreteStateMachine` directly.

```
use IronBound\State\Graph\{GraphId, MutableGraph};
use IronBound\State\ConcreteStateMachine;
use IronBound\State\StateMediator\PropertyStateMediator;
use IronBound\State\State\{StateId, MutableState, StateType};
use IronBound\State\Transition\{TransitionId, MutableTransition};

$graph = new MutableGraph(new GraphId('status'));
$graph->addState(new MutableState(new StateId('pending'), StateType::INITIAL()));
$graph->addState(new MutableState(new StateId('published')));
$graph->addTransition(new MutableTransition(
    new TransitionId('publish'),
    [ new StateId('pending') ],
    new StateId('published')
));

$mediator = new PropertyStateMediator('status');

$stateMachine = new ConcreteStateMachine($mediator, $graph->toImmutable(), $subject);
```

However, you may prefer an alternate construction style where you use a Factory that is preconfigured.

```
use IronBound\State\Graph\GraphId;
use IronBound\State\Factory\StateMachineFactory;

/** @var StateMachineFactory $factory*/
$factory->make($subject, new GraphId('status'));
```

The recommended way to do this is to use the `StateMachineFactoryConfigurator` class to do the heavy lifting based on a configuration array.

```
use IronBound\State\Factory\StateMachineFactoryConfigurator;
use IronBound\State\Graph\GraphId;
use IronBound\State\State\StateType;
use IronBound\State\StateMachine;
use IronBound\State\Transition\Evaluation;

$config = [
    [
        // The test determines which Graphs apply to the given subject. This means that
        // GraphIds only have to be unique to the subject type instead of globally.
        'test'   => [
            // This particular test type checks if the subject is an instance of the given class.
            'class' => 'Order',
        ],
        // The list of all the graphs for this subject.
        'graphs' => [
            'payment'  => [
                'mediator'    => [
                    // Use a mediator that checks against an object's properties.
                    'property' => 'paymentStatus',
                ],
                // The list of all the available states
                'states'      => [
                    'unpaid'   => [
                        // Specifies the StateType manually. The default is NORMAL.
                        'type' => StateType::INITIAL,
                    ],
                    // If you don't need any extra configuration options,
                    // you can just specify a string with no key.
                    'processing',
                    'paid',
                    'refunded' => [
                        'type' => StateType::FINAL,
                        // Custom defined attributes.
                        'attributes' => [
                            'label' => 'Refunded',
                        ],
                    ],
                ],
                // The list of all the available transitions
                'transitions' => [
                    'pay'      => [
                        // The list of states this transition can be applied from
                        'from' => 'unpaid',
                        // The state the subject will be in after transitioning.
                        'to'   => 'processing',
                        // Custom defined attributes.
                        'attributes' => [
                            'label' => 'Pay',
                        ],
                    ],
                    'complete' => [
                        'from' => 'processing',
                        'to'   => 'paid',
                    ],
                    'refund'   => [
                        'from' => [ 'processing', 'paid' ],
                        'to'   => 'refunded',
                        // Use a guard to add constraints to when a transition is available.
                        'guard' => static function(StateMachine $machine) {
                            if ($machine->getSubject()->createdAt + WEEK_IN_SECONDS < time()) {
                                return Evaluation::invalid('The refund window has expired.');
                            }

                            return Evaluation::valid();
                        }
                    ],
                ],
            ],
            'delivery' => [
                'mediator'    => [
                    'property' => 'deliveryStatus',
                ],
                'states'      => [
                    'processing' => [
                        'type' => StateType::INITIAL,
                    ],
                    'in-transit',
                    'delivered'  => [
                        'type' => StateType::FINAL,
                    ]
                ],
                'transitions' => [
                    'drop-at-carrier' => [
                        'from' => 'processing',
                        'to'   => 'in-transit',
                    ],
                    'deliver'         => [
                        'from' => 'in-transit',
                        'to'   => 'delivered',
                    ],
                ],
            ],
        ],
    ],
    [
        'test'   => [
            'class' => 'BlogPost',
        ],
        'graphs' => [
            'states'      => [
                'draft'     => [
                    'type' => StateType::INITIAL,
                ],
                'published' => [
                    'type' => StateType::FINAL,
                ],
            ],
            'transitions' => [
                'publish' => [
                    'from' => 'draft',
                    'to'   => 'published',
                ],
            ],
        ],
    ],
];

$stateMachineFactory = (new StateMachineFactoryConfigurator())->configure( $config );

$paymentStateMachine = $stateMachineFactory->make(new Order(), new GraphId('payment'));
$deliveryStateMachine = $stateMachineFactory->make(new Order(), new GraphId('delivery'));
$blogPostStateMachine = $stateMachineFactory->make(new BlogPost(), new GraphId('status'));
```

Events
------

[](#events)

IronBound-State integrates with the [PSR-14 Event Dispatcher spec](https://www.php-fig.org/psr/psr-14/) to customize behavior and listen for actions.

You can provide the `ConcreteStateMachine` with an `EventDispatcherInterface` instance by calling `ConcreteStateMachine::setEventDispatcher`. The following events are currently supported.

### [`TestTransitionEvent`](src/Event/TestTransitionEvent.php)

[](#testtransitionevent)

Called during the evaluation process after determining that the transition is available, and it's guard returned a valid evaluation. Call `TestTransitionEvent::reject($reason)` to dynamically prevent a transition from being applied.

### [`BeforeTransitionEvent`](src/Event/BeforeTransitionEvent.php)

[](#beforetransitionevent)

Called before updating a subject's state in response to a transition being applied.

### [`AfterTransitionEvent`](src/Event/AfterTransitionEvent.php)

[](#aftertransitionevent)

Called after updating a subject's state in response to a transition being applied.

###  Health Score

32

—

LowBetter than 72% of packages

Maintenance53

Moderate activity, may be stable

Popularity10

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 95.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 ~10 days

Total

6

Last Release

2282d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/c348d8c0ee55f04ab227c1084486ec12037713b2919f91f16c774625a33391b9?d=identicon)[TimothyBJacobs](/maintainers/TimothyBJacobs)

---

Top Contributors

[![TimothyBJacobs](https://avatars.githubusercontent.com/u/3460448?v=4)](https://github.com/TimothyBJacobs "TimothyBJacobs (20 commits)")[![szepeviktor](https://avatars.githubusercontent.com/u/952007?v=4)](https://github.com/szepeviktor "szepeviktor (1 commits)")

---

Tags

phpstate-machine

###  Code Quality

TestsPHPUnit

Code StylePHP\_CodeSniffer

### Embed Badge

![Health badge](/badges/ironbound-state/health.svg)

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

###  Alternatives

[sylius/refund-plugin

Plugin provides basic refunds functionality for Sylius application.

691.7M14](/packages/sylius-refund-plugin)[seboettg/citeproc-php

Full-featured CSL processor (https://citationstyles.org)

761.2M19](/packages/seboettg-citeproc-php)[timeweb/phpstan-enum

Enum class reflection extension for PHPStan

443.2M21](/packages/timeweb-phpstan-enum)[php-unit-conversion/php-unit-conversion

A fully PSR-4 compatible PHP library for converting between standard units of measure.

681.2M1](/packages/php-unit-conversion-php-unit-conversion)[open-feature/sdk

PHP implementation of the OpenFeature SDK

39514.9k15](/packages/open-feature-sdk)

PHPackages © 2026

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