jeroen-g / statinator
新一代 PHP 状态机
Requires
- php: ^7.4|^8.0
Requires (Dev)
- infection/infection: 0.20
- phpunit/phpunit: ^9.2
- symplify/easy-coding-standard: ^8.3
This package is auto-updated.
Last update: 2024-09-19 02:46:56 UTC
README
新一代 PHP 状态机和状态图。
安装
composer require jeroen-g/statinator
使用方法
想象一下,您想为可以处于开启或关闭状态的灯开关创建一个状态机。其图表看起来如下所示
此状态机的 Statinator 配置看起来如下所示
$config = [ 'states' => [ 'LIGHTS_ON', 'LIGHTS_OFF', ], 'transitions' => [ 'FLICK_ON' => [ 'from' => ['LIGHTS_OFF'], 'to' => ['LIGHTS_ON'], ], 'FLICK_OFF' => [ 'from' => ['LIGHTS_ON'], 'to' => ['LIGHTS_OFF'], ], ], ];
然后在您的应用程序中,您应该使用此配置实例化 Statinator。
use JeroenG\Statinator\Statinator; $statinator = new Statinator($config);
Statinator 接受第二个参数,该参数是实现 ActionRepositoryInterface
的存储库,这(可选)存储成功和失败的操作。
您想在状态机中使用的任何对象都应该实现 StatableInterface
接口。对于灯开关的示例,可能是这样的
use JeroenG\Statinator\StatableInterface; class LightSwitch implements StatableInterface { private string $currentState; public function __construct(string $initialState) { $this->currentState = $initialState; } public function getState(): string { return $this->currentState; } public function setState(string $to): void { $this->currentState = $to; } }
在您的代码的任何地方,您都可以使用 Statinator 实例来获取状态机并与其状态和转换交互。
$lightSwitch = new LightSwitch('LIGHTS_OFF'); $sm = $statinator->get($lightSwitch); $sm->getState(); // LIGHTS_OFF $sm->can('FLICK_ON'); // true $sm->can('FLICK_OFF'); // false $sm->apply('FLICK_ON'); $sm->getState(); // LIGHTS_ON $sm->can('FLICK_ON'); // false $sm->can('FLICK_OFF'); // true
虽然看到对象从一个状态移动到另一个状态相当酷,但真正的力量在于您可以定义的转换操作。
在状态改变之前和之后,状态机执行任何可用的操作。您可以在全局配置中定义操作,或通过在 Statinator 上使用设置器。
// Using the configuration $config = [ // ... 'transitions' => [ 'FLICK_ON' => [ 'from' => ['LIGHTS_OFF'], 'to' => ['LIGHTS_ON'], 'on' => [ 'entry' => NotifyLightsAreOn::class, 'exit' => NotifyLightsAreOff::class, ], ], // ... ], ]; // Or using a setter $statinator->onEntry('FLICK_ON', NotifyLightsAreOn::class); $statinator->onExit('FLICK_ON', NotifyLightsAreOff::class);
操作可以是 callable
或实现 ActionableInterface
的类。
$statinator->onEntry('FLICK_OFF', fn(StateMachineInterface $stateMachine, string $transition) => var_dump('Called it!'));
use JeroenG\Statinator\ActionableInterface; use JeroenG\Statinator\StateMachineInterface; class NotifyLightsAreOn implements ActionableInterface { private StateMachineInterface $stateMachine; private string $transition; public function getState(): string { return $this->stateMachine->getState(); } public function execute(StateMachineInterface $stateMachine, string $transition): void { $this->stateMachine = $stateMachine; $this->transition = $transition; $notifier = new MyNotifier(); $notifier->send('Lights are turned on'); } public function getTransition(): string { return $this->transition; } }
如果您的操作实现 ActionableInterface
,则可以使用在实例化 Statinator 时传递的存储库进行保存。此软件包附带一个默认使用的 ArrayActionRepository
,该存储库不持久化数据。另一种可能性是 LogActionRepository
,它需要一个符合 PSR 的记录器,数据将在此持久化。当然,您也可以创建自己的存储库(可能是一个使用数据库的存储库),只要它实现了 ActionRepositoryInterface
。
贡献
项目包括一个 Makefile,用于运行安装、运行测试和检查代码风格。