定制 llbbl/enum-state-machine 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

llbbl/enum-state-machine

最新稳定版本:v0.1.0

Composer 安装命令:

composer require llbbl/enum-state-machine

包简介

Zero-configuration, framework-agnostic PHP state machine driven by Enums and Attributes.

README 文档

README

Zero-configuration, framework-agnostic PHP state machine driven by Enums and Attributes.

Instead of bloated configuration arrays, you declare transitions, guards, and side-effects directly on the enum that represents your state — so the enum is the documentation, fully typed and statically analyzable.

use EnumStateMachine\Attributes\Transition;
use EnumStateMachine\Attributes\StateMachineConfig;

#[StateMachineConfig(dispatchEvents: true)]
#[Transition(to: self::Cancelled, guard: NotYetShippedGuard::class)] // wildcard: any state → Cancelled
enum OrderState: string
{
    case Pending = 'pending';

    #[Transition(to: self::Processing, after: ChargeCreditCardHook::class)]
    case Paid = 'paid';

    #[Transition(
        to: self::Shipped,
        guard: HasValidAddressGuard::class,
        before: ReserveInventoryHook::class,
        after: SendTrackingEmailHook::class,
    )]
    case Processing = 'processing';

    case Shipped = 'shipped';
    case Cancelled = 'cancelled';
}
use EnumStateMachine\StateMachine;
use EnumStateMachine\Exceptions\InvalidTransitionException;

// Construct from your model's enum-typed state (`$order->state` is typed
// `OrderState`) for full PHPStan narrowing of `transitionTo()` / `getCurrentState()`.
$machine = new StateMachine($order->state);

if ($machine->can(OrderState::Shipped, context: $order)) {
    // show the "Ship" button
}

try {
    $order->state = $machine->transitionTo(OrderState::Shipped, context: $order);
} catch (InvalidTransitionException $e) {
    // no such transition, or a guard rejected it
}

Core principles

  • The enum is the truth — transitions, guards, and side-effects live on the enum case.
  • Strictly typed — full IDE autocompletion and PHPStan/Psalm support.
  • Agnostic — vanilla PHP, Laravel, Symfony, anything. Optional PSR-11 container (DI for guards/hooks) and PSR-14 dispatcher (transition events); neither is required.

Requirements

  • PHP >= 8.1 (Enums + Attributes)
  • Optional: psr/container (resolve guards/hooks via DI), psr/event-dispatcher (emit transition events)

Installation

composer require llbbl/enum-state-machine

Concepts

Piece Role
#[Transition(to, guard, before, after, includeSelf)] Declares an allowed transition. On a case = from that state; on the enum class = wildcard from any state. Repeatable.
#[StateMachineConfig(dispatchEvents, event)] Class-level config (event dispatching toggle / custom event).
GuardInterface __invoke($from, $to, $context): bool — vetoes a transition. Must be side-effect-free (also run by can()).
StateHookInterface __invoke($from, $to, $context): voidbefore/after side-effects.
StateTransitioned PSR-14 event emitted after a successful transition.
StateMachine The engine: can(), transitionTo(), getCurrentState().

Order of a transition: guardsbefore hooks → state changes → after hooks → event. Guards/before-hook failures propagate raw and leave state unchanged; an after-hook failure leaves the state changed but throws HookExecutionException.

Development setup

This repo uses mise to pin PHP and just as the task runner.

1. Bootstrap the toolchain (macOS, one-time)

just php setup      # Homebrew C libs + builds the pinned PHP against openssl@3
just install        # composer install

The PHP toolchain recipes live in a php module (just php <recipe>):

Recipe Purpose
just php setup One-time bootstrap (Homebrew libs + build the pinned PHP).
just php version Print the active PHP version.
just php latest Latest stable (non-RC) PHP vs the current pin.
just php floor Oldest php.net active-support PHP — the compatibility floor.
just php bump [VERSION] Repin mise.toml to the latest stable (or an explicit version); refuses RCs.

just php setup compiles PHP from source via mise. Two macOS gotchas it handles for you:

  • openssl — the mise php plugin hardcodes the EOL openssl@1.1, which yields a PHP with no working TLS wrapper (Composer-over-https breaks). The recipe points the build at openssl@3 via brew --prefix.
  • link libs — it installs gd, icu4c, libzip, oniguruma, libxml2 (the libs the build force-links) so ./configure doesn't abort. The state machine uses none of these at runtime; they're build-time link deps of the PHP binary.

If the build stops at a checking for … no line for a different lib, install the matching Homebrew formula and re-run just php setup.

2. Everyday commands

just            # list recipes
just test       # run the Pest suite
just stan       # PHPStan at max level
just qa         # stan + test (the quality gate)
just coverage   # tests with coverage

All recipes run through the mise-pinned PHP.

3. Testing on older PHP (8.1–8.3)

The library supports PHP >= 8.1, but the dev toolchain doesn't: Pest 3 pulls in symfony/* v8, which requires PHP >= 8.4.1. So the committed composer.lock only installs on 8.4+, and GitHub CI runs the full suite on the currently-supported versions (8.4 and 8.5) with a reproducible composer install.

Older versions are exercised locally via Docker, where each version resolves its own compatible dependency set:

just legacy all        # 8.1 (lint) + 8.2 + 8.3 (full Pest suite)
just legacy run 8.2    # a single version
just legacy build      # rebuild the images after editing docker/Dockerfile
  • 8.2 / 8.3 run the full Pest suite — the container does a composer update (resolving symfony v7, which Pest 3 also supports) before testing.
  • 8.1 can't install Pest 3 at all, so it only syntax-checks src/ (php -l) to defend the runtime floor.

The repo is mounted read-only and copied inside the container, so a legacy run's composer update never rewrites your 8.4-resolved host composer.lock. Requires Docker (docker compose); the recipes live in the legacy module (compose.yaml + docker/).

License

MIT

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 2
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-06-11

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固