PHPackages                             noem/state-machine-loader - 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. noem/state-machine-loader

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

noem/state-machine-loader
=========================

Constructs usable state machine instances from various data sources (Array, JSON,YAML)

04401[1 PRs](https://github.com/NoemPHP/state-machine-loader/pulls)PHP

Since Feb 3Pushed 2y ago1 watchersCompare

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

READMEChangelogDependenciesVersions (2)Used By (0)

State Machine Loader
====================

[](#state-machine-loader)

[![CI](https://github.com/NoemPHP/state-machine-loader/actions/workflows/ci.yml/badge.svg)](https://github.com/NoemPHP/state-machine-loader/actions/workflows/ci.yml)

Creates [State Machine](https://noemphp.github.io/state-machine/) instances from various sources.

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

[](#installation)

Install this package via composer:

`composer require noem/state-machine-loader`

Schema
------

[](#schema)

All input data is validated against a JSON schema using [justinrainbow/json-schema](https://github.com/justinrainbow/json-schema). The raw schema file can be found at [src/schema.json](https://github.com/NoemPHP/state-machine-loader/blob/master/src/schema.json)Below is a description of all the relevant entities:

### State

[](#state)

KeyTypeRequiredExampleCommenttransitionsarray&lt;[Transition](#transition)&gt;-`["target-state"]`Define which states can be reached from this statechildren`object`-`{"subState": {}}``Dictionary`. Recursionparallel`boolean`-`true`Flag this state as parallel.
All of its children will be active at the same timeinitial`string`-`"subState"`Only used for hierarchical states.
Determines which child state is initially active.
 Defaults to the first child if omittedonEntry[Callback](#callback)-`"my_php_function"`
`"@myContainerEntry"`An action to run when this state is entered.onExit[Callback](#callback)-`"my_php_function"`
`"@myContainerEntry"`An action to run when this state is exited.context`string`,`object`-`{"hello": "world"}}`
`"@myContainerEntry"`Initial context data.### Transition

[](#transition)

As an alternative shorthand, you can just define a `string` with the target state. This will result in a simple transition that is not enabled by any event or guard and thus will be immediately enabled as soon as the state machine is triggered by any event. This can be useful for chaining transitions, eg. when you are more interested in the series of enEntry/onExit events than the intermediate states. The full definition of a transition is an `object` though:

KeyTypeRequiredExampleCommenttargetstring\*`my-state`guard`string`,`array`-`"MyEventClassName"`### Callback

[](#callback)

Event handlers (guards, actions, entry/exit handlers) are defined with a flexible syntax

#### Shorthand method

[](#shorthand-method)

In its simplest form, this is just a `string` which is checked for `is_callable()` (-&gt;allowing you to pass the names of PHP functions or static methods).

```
my_state:
    action: var_dump
```

However, it is also possible to pull callbacks from a container:

You can optionally pass a PSR-11 `ContainerInterface` into the loader object. It will be used whenever a callback is prefixed with `"@"`. For example, if you define `onEntry: "@onEnterFoo"`, this will result in `$callback = $container->get('onEnterFoo')`. You can use this to integrate your framework's DI container into the FSM's event handling.

```
my_state:
    action: @onPostRequest
```

#### Extended syntax

[](#extended-syntax)

Shorthands are great for prototyping and/or very *functional* codebases, but they make code reuse hard due to the lack of parametrization mechanisms. For more flexibility, you may opt to define your handlers as objects.

##### Factory

[](#factory)

The factory allows you to configure a "function that returns a function" with the arguments that you define next to it.

```
my_state:
    action:
        type: factory
        factory: createMyStateAction
        arguments:
            - Hello world
            - false
```

This assumes a function like this in your code:

```
function createMyStateAction(string $greeting, bool $isError){

    return function(object $input) use ($greeting, $echo){
        $input->greeting = $greeting;
        $input->isError
        return $input;
    }

}
```

This pattern allows you to reuse the same handlers and customize their behaviour from YAML. This can be especially useful for writing guards: Say you want to ensure a state has been active for at least 5 seconds. Without factories, you are more or less forced to create some version of a `hasBeenInStateForFiveSeconds` function. If you want to use the same logic to wait for 10 seconds elsewhere in your application, you're in a tough situation now. With a factory definition, you can instead write a `createTimeoutGuard` which can return guards for any interval you want.

##### Inline

[](#inline)

Inline handlers are a way to write your handlers directly into YAML, rather than defining them as functions in a service container.

```
my_state:
    onEntry:
        type: inline
        # language=injectablephp
        callback: |
            $context = $machine->context($transition->source());
            $context['greeting'] = 'Hello World!';
```

Since `action` and `guard` callbacks leverage PSR-14-style parameter inspections, it is neccessary to specify an additional argument for them:

```
baz:
    action:
      # Note the additional 'trigger'
      type: 'inline'
      callback: |
          echo 'Hello ' . $trigger;
      trigger: '\Stringable'
```

This is useful if you want to keep things simple and don't need to reuse the handler elsewhere in your codebase. It is also a great way to start prototyping quickly. Since this is intended for basic scripting, you only supply the *function body itself*. You can use the following variables within your inline callbacks:

###### Types `onEntry` &amp; `onExit`

[](#types-onentry--onexit)

- `$state` - The state object where the handler is registered
- `$from` - The state that is being transitioned away from. (In simple machines, this might be the same as `$state`, but it is very much possible for a machine to be in many states at once)
- `$machine` - The state machine object

###### Type `action`

[](#type-action)

- `$trigger` - The object that triggered the action
- `$state` - The state object where the handler is registered
- `$machine` - The state machine object

###### Type `guard`

[](#type-guard)

- `$trigger` - The object that triggered the transition
- `$transition` - The transition object
- `$machine` - The state machine object

---

Full example
------------

[](#full-example)

All event handlers are assumed to be configured in a Service Container.

```
off:
    transitions:
        - on # Shorthand used

on:
    parallel: true
    context:
        hello: "world"
    onEntry: '@onBooted'
    children:
        foo:
            action: '@sayMyName'

        bar:
            action: '@sayMyName'
            parallel: true
            children:
                bar_1:
                    action: '@sayMyName'
                    children:
                        bar_1_1:
                            transitions:
                            - target: 'bar_1_2'
                              guard: '@guardBar_1_2'
                        bar_1_2:
                            transitions:
                            - target: 'bar_1_1'
                              guard:
                                  type: factory
                                  # Executes a function that creates the actual guard based on the given parameters
                                  factory: '@myGuardFactory'
                                  arguments:
                                      - 'hello'
                                      - 'world'
                bar_2:
                    action: '@sayMyName'

        baz:
            initial: 'substate2' # if not specified, it would use the first child, 'substate1'
            action:
              - '@sayMyName'
              - type: factory
                factory: '@myActionFactory'
                arguments:
                    - 'lorem'
                    - '%getIpsum%'
              # Write raw PHP directly!
              # Note the additional 'trigger'
              - type: 'inline'
                callback: |
                    echo 'Hello World';
                trigger: '\stdClass'
            children:
                substate1:
                    action: '@sayMyName'

                substate2:
                    action: '@sayMyName'
                    transitions:
                        -   target: 'substate3'
                            guard:
                            # Multiple guards for one transition are possible. Any of them can allow the transition
                              - '@someOtherGuard'
                              - '@guardSubstate3'
                            # Write raw PHP directly!
                              - type: 'inline'
                                callback: |
                                    return false;
                                trigger: '\stdClass'
                substate3:
                    action: '@sayMyName'

    transitions:
        # If an exception is used as a trigger,
        # it can be used to perform a graceful shutdown
        -   target: error
            guard: Throwable

error:
    onEntry:
      - '@onException'
      - '@anotherErrorHandler'
    context: '@helloWorldService'
    transitions:
        - off
```

###  Health Score

16

—

LowBetter than 5% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity13

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity21

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/16e124446e13d0c8773106688a571f7afc645474750a5d8e7489e568f67d2822?d=identicon)[Biont](/maintainers/Biont)

---

Top Contributors

[![Biont](https://avatars.githubusercontent.com/u/4208996?v=4)](https://github.com/Biont "Biont (61 commits)")

---

Tags

fsmhsmphpstate-machine

### Embed Badge

![Health badge](/badges/noem-state-machine-loader/health.svg)

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

###  Alternatives

[maksyutin/yii2-dual-list-box

Dual list box Widget for Yii 2

138.8k1](/packages/maksyutin-yii2-dual-list-box)

PHPackages © 2026

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