PHPackages                             coff/state-machine-framework - 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. coff/state-machine-framework

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

coff/state-machine-framework
============================

State Machine Framework PHP component for designing state machines

v1.0.0(7y ago)017MITPHPPHP ^7.0

Since Nov 23Pushed 7y ago1 watchersCompare

[ Source](https://github.com/coff/php-state-machine-framework)[ Packagist](https://packagist.org/packages/coff/state-machine-framework)[ RSS](/packages/coff-state-machine-framework/feed)WikiDiscussions master Synced 3d ago

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

State Machine Framework for PHP
===============================

[](#state-machine-framework-for-php)

Maybe state machines are not what you usually do with PHP but when you do... just use this. This simple yet powerful framework will keep your state machines within their desired state transition cycles. You can also modify their behavior whilst running or just configure them dynamically and launch. You can define state transition conditions you want based upon anonymous functions or class methods. Fire events on each state transition with your favorite event dispatcher.

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

[](#installation)

Easiest way is to use composer:

```
$ composer require coff/state-machine-framework
```

Alternatively just clone repository:

```
$ git clone https://github.com/coff/php-state-machine-framework.git
```

and then checkout specific tag:

```
$ git checkout tags/v0.3
```

Usage example
-------------

[](#usage-example)

### States' dictionary

[](#states-dictionary)

For clarity each state machine should have its own state dictionary defined.

```

    /**
     * @method static DRAFT()
     * @method static SENT()
     * ... // this should make your IDE believe these methods exist
     *
     */
    class PetitionEnum extends StateEnum {
        const __default     = self::DRAFT,
              DRAFT         = 'draft',
              SENT          = 'sent',
              VOTED         = 'voted',
              ACCEPTED      = 'accepted',
              REJECTED      = 'rejected',
              CANCELED      = 'canceled';

              // States names should be defined lowercase without spaces and special characters due to
              // automatically determined assertion method names when in use with DefaultCallbackAssertion
              // @todo replace DefaultCallbackAssertion behavior in this matter

    }
```

### Machine class

[](#machine-class)

```
    class Petition extends Machine {

        protected $votesYes, $votesNo;

        public function init() {
            $this->setInitState(PetitionEnum::DRAFT());

            // defines machine's allowed behavior
            $this
                // prevents changing state upon assertion when AlwaysFalseAssertion is given
                ->allowTransition(PetitionEnum::DRAFT(), PetitionEnum::SENT(), new AlwaysFalseAssertion())
                ->allowTransition(PetitionEnum::DRAFT(), PetitionEnum::CANCELED(), new AlwaysFalseAssertion())

                // when no Assertion is given uses DefaultCallbackAssertion which calls assertXToY methods
                ->allowTransition(PetitionEnum::SENT(), PetitionEnum::VOTED())
                ->allowTransition(PetitionEnum::VOTED(), PetitionEnum::ACCEPTED())
                ->allowTransition(PetitionEnum::VOTED(), PetitionEnum::REJECTED())
                ;

        }

        public function send()
        {
            // shall throw an exception if current state is not DRAFT because it wasn't allowed transition
            $this->setMachineState(PetitionEnum::SENT());
        }

        public function cancel()
        {
            // shall throw an exception if current state is not DRAFT because it wasn't allowed transition
            $this->setMachineState(PetitionEnum::CANCELED());
        }

        public function setVotes($ya, $nay)
        {
            $this->votesYes = $ya;
            $this->votesNo = $nay;
        }

        public function assertSentToVoted()
        {
            // Method name used here is based upon DefaultCallbackAssertion. This can be changed though.
            return (null !== $this->votesYes && null !== $this->votesNo) ? true : false;
        }

        public function assertVotedToAccepted()
        {
            // condition for transition from state VOTED to ACCEPTED
            return $this->votesYes > $this->votesNo ? true : false;
        }

        public function assertVotedToRejected()
        {
            // condition for transition from state VOTED to REJECTED
            return $this->votesYes votesNo ? true : false;
        }

        public function onTransition(Transition $transition)
        {
            // for purpose of this example we only echo this transition but you can easily dispatch an event from here
            echo 'State changed from ' . $transition->getFromState() . ' to ' . $transition->getToState() . PHP_EOL;
        }
    }
```

### Machine in-use

[](#machine-in-use)

```
    $p = new Petition();
    $p->init();

    $p->run();
    //

    $p->send();
    // State changed from draft to sent

    $p->run();
    //

    $p->setVotes(5,1);

    $p->run();
    // State changed from sent to voted
    // State changed from voted to accepted

```

### Transition object

[](#transition-object)

Each transition object should have one or more assertion objects attached.

*Remark: By default (when no assertion object is given as parameter) `Machine::allowTransition()` method attaches `DefaultCallbackAssertion`.*

### Assertion behaviors

[](#assertion-behaviors)

#### AlwaysTrueAssertion

[](#alwaystrueassertion)

Results in automatic transition when machine is launched.

Be aware:

```
    $machine
        ->allowTransition(MachineEnum::ONE(), MachineEnum::TWO(), new AlwaysTrueAssertion)
        ->allowTransition(MachineEnum::TWO(), MachineEnum::ONE(), new AlwaysTrueAssertion)

    $machine->run();
    // this will result in endless loop of state changes
```

#### AlwaysFalseAssertion

[](#alwaysfalseassertion)

Results in no transition when machine is launched. Use this kind of assertion when machine state is supposed to be changed upon `setMachineState()` method call only.

#### DefaultCallbackAssertion

[](#defaultcallbackassertion)

Calls `assertXToY` method on machine object (or other object if specified) and makes transition decision upon its return.

#### CommonCallbackAssertion

[](#commoncallbackassertion)

Calls `assertTransition` method on machine object (or other object if specified) and makes transition decision upon its return.

#### CallbackAssertion

[](#callbackassertion)

Calls user specified method to assert if state transition should proceed.

###  Health Score

26

—

LowBetter than 43% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity6

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity60

Established project with proven stability

 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.

###  Release Activity

Cadence

Every ~9 days

Total

5

Last Release

2692d ago

Major Versions

v0.3 → v1.0.02018-12-06

v1.0.0 → v2.0.0-alpha2018-12-30

### Community

Maintainers

![](https://www.gravatar.com/avatar/2b28b2b3ed2956f8e7e09346399a1da038e30d831ca3e5ecd308e888237b6aa9?d=identicon)[coff](/maintainers/coff)

---

Top Contributors

[![coff](https://avatars.githubusercontent.com/u/3470380?v=4)](https://github.com/coff "coff (27 commits)")

---

Tags

phpstate-machinestateful

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/coff-state-machine-framework/health.svg)

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

###  Alternatives

[apoutchika/loremipsum-bundle

Generate paragraphs, sentences and words for your development.

1259.8k](/packages/apoutchika-loremipsum-bundle)[hiromi2424/collectionable

Collectionable plugin for CakePHP

172.3k](/packages/hiromi2424-collectionable)

PHPackages © 2026

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