Фреймворк машины состояния PHP
Я сомневаюсь, что есть какие-либо рамки государственной машины, такие как https://github.com/pluginaweek/state_machine для PHP.
мне пришлось определить много логических предложений if-else, и я хотел бы, чтобы что-то помогло сделать его более интересным, просто определив:
- условие, необходимое для перехода
- состояние после переходного
затем это можно повторно использовать для проверки соответствия условий или нет, для пример
$customer->transition('platinum');
Я ожидаю, что эта строка кода неявно проверит, может ли клиент переходить или нет. Или явно проверьте по:
$customer->canTransitTo('platinum');
спасибо заранее, noomz
6 ответов
Я не знаю такой структуры (что не означает, что она не существует). Но пока не как функция упакована как связанная структура,государственного образца довольно просто реализовать. Рассмотрим эту наивную реализацию ниже:
interface EngineState
{
public function startEngine();
public function moveForward();
}
class EngineTurnedOffState implements EngineState
{
public function startEngine()
{
echo "Started Engine\n";
return new EngineTurnedOnState;
}
public function moveForward()
{
throw new LogicException('Have to start engine first');
}
}
class EngineTurnedOnState implements EngineState
{
public function startEngine()
{
throw new LogicException('Engine already started');
}
public function moveForward()
{
echo "Moved Car forward";
return $this;
}
}
после того, как вы определили состояния, вам просто нужно применить их к вашему основному объекту:
class Car implements EngineState
{
protected $state;
public function __construct()
{
$this->state = new EngineTurnedOffState;
}
public function startEngine()
{
$this->state = $this->state->startEngine();
}
public function moveForward()
{
$this->state = $this->state->moveForward();
}
}
и тогда вы можете сделать
$car = new Car;
try {
$car->moveForward(); // throws Exception
} catch(LogicException $e) {
echo $e->getMessage();
}
$car = new Car;
$car->startEngine();
$car->moveForward();
для уменьшения чрезмерно больших операторов if / else это должно быть достаточный. Обратите внимание, что возврат нового экземпляра состояния при каждом переходе несколько неэффективен. Как я уже сказал, это наивная реализация, чтобы проиллюстрировать этот момент.
Я работал над простой библиотекой конечных автоматов PHP, похожей на rails state_machine. Код здесь: https://github.com/chriswoodford/techne/tree/v0.1
пример автомобиля, похожий на выбранный ответ (выше), будет выглядеть примерно так:
инициализации
$machine = new StateMachine\FiniteStateMachine();
$machine->addEvent('start', array('parked' => 'idling'));
$machine->addEvent('drive', array('idling' => 'driving'));
$machine->addEvent('stop', array('driving' => 'idling'));
$machine->addEvent('park', array('idling' => 'parked'));
$machine->setInitialState('parked');
использование
$machine->start();
echo $machine->getCurrentStatus();
// prints "idling"
$machine->drive();
echo $machine->getCurrentStatus();
// prints "driving"
$machine->stop();
echo $machine->getCurrentStatus();
// prints "idling"
$machine->park();
echo $machine->getCurrentStatus();
// prints "parked"
ему не хватает явно определенного интерфейса, поскольку он использует магический метод __call() для принятия сообщения, но это может быть легко разрешено с помощью адаптер.
Я использовал этот https://github.com/yohang/Finite что довольно мощно, однако документы не так подробны. Если вы familliar с государственными машинами, то у вас не должно быть никаких проблем.
Я написал государственную машину для php. Я уверен, что вы уже давно нашли решение. Но для людей, посещающих эту страницу, вы можете попробовать эту государственную машину.
https://github.com/definitely246/state-machine
чтобы использовать его, вы определяете обработчики событий перехода в классы. Затем нужно определить переходы. Конечная машина может быть настроена для выполнения других задач, но вот основы.
class Event1ChangedState1ToState2
{
public function allow($context)
{
return true;
}
public function handle($context)
{
if (!$context->statesChanged) $context->statesChanged = 0;
print "state1 -> state2\n";
return $context->statesChanged++;
}
}
class Event1ChangedState2ToState1
{
public function allow($context)
{
return true;
}
public function handle($context)
{
print "state2 -> state1\n";
return $context->statesChanged++;
}
}
затем вы можете определить переходы, которые изменяют состояния при запуске события.
$transitions = [
[ 'event' => 'event1', 'from' => 'state1', 'to' => 'state2', 'start' => true],
[ 'event' => 'event1', 'from' => 'state2', 'to' => 'state1' ],
];
$fsm = new StateMachine\FSM($transitions);
print $fsm->state() . PHP_EOL; // 'state1'
$fsm->event1(); // returns 1, prints 'state1 -> state2'
print $fsm->state() . PHP_EOL; // 'state2'
$fsm->event1(); // returns 2, prints 'state2 -> state1'
print $fsm->state() . PHP_EOL; // 'state1'
вы можете установить с composer
composer require definitely246/state-machine
Я создал Smalldb framework для реализации уровня модели веб-приложения с использованием государственных машин. Он предназначен для работы непосредственно с базой данных SQL, где каждая строка таблицы SQL представляет экземпляр машины состояния (поэтому машины состояния являются постоянными).
Он имеет управление доступом на основе ролей, поэтому вы можете указать в определении государственной машины, какие переходы разрешены для каких пользователей (он также может иметь дело с владельцами экземпляра государственной машины или компоненты более сложных объектов).
для ускорения разработки Smalldb может загружать диаграммы состояний в GraphML, созданные с помощью редактора yEd, поэтому вы можете нарисовать диаграмму состояния, а затем напрямую использовать ее в своем приложении, а также в своей документации. Также в разработке находится собственный редактор (jQuery widget + desktop wrapper). Для целей отладки и онлайн-документации в приложении Smalldb может создавать диаграммы состояний с помощью Graphviz.