Фреймворк конечного автомата PHP - PullRequest
19 голосов
/ 25 ноября 2010

Я сомневаюсь, что существует какой-либо фреймворк, например https://github.com/pluginaweek/state_machine для PHP.

Мне пришлось определить множество логических предложений if-else, и я хотел бы, чтобы что-то помогло сделать его более увлекательным, просто определив:

  1. Условие, необходимое для перехода
  2. Состояние после перехода

Затем это можно использовать повторно для проверки соответствия условий или нет, например

$customer->transition('platinum');

Я ожидаю, что эта строка кода будет неявно проверять, может ли клиент перейти или нет. Или явно проверьте по:

$customer->canTransitTo('platinum');

Заранее спасибо, noomz

Ответы [ 7 ]

40 голосов
/ 25 ноября 2010

Я не знаю такой структуры (это не значит, что она не существует).Но, хотя и не такая функциональная возможность, как связанная структура, шаблон State довольно прост в реализации.Рассмотрим эту наивную реализацию ниже:

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 этого должно быть достаточно.Обратите внимание, что возвращение нового экземпляра состояния при каждом переходе несколько неэффективно.Как я уже сказал, это наивная реализация, чтобы проиллюстрировать это.

9 голосов
/ 25 ноября 2010
4 голосов
/ 19 ноября 2012

Я работал над простой библиотекой конечных автоматов 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 () для приема сообщений, но это можно легко решить с помощью адаптера .

2 голосов
/ 07 октября 2015

Я использовал этот https://github.com/yohang/Finite, который довольно мощный, однако документы не настолько подробны. Если вы знакомы с конечными автоматами, у вас не должно быть никаких проблем.

1 голос
/ 10 декабря 2018

Для записи я пишу (еще один) конечный автомат

https://github.com/EFTEC/StateMachineOne

Однако он основан на автоматизации, а не на событии (однако можно использовать поле как событие).Переход состояния инициируется значениями, вручную или кодом.

Например, пример парковки:

, где педаль, ключ, газ, скорость и тормоз - это поля, определяемые и управляемые кодом.

$smachine->addTransition(PARKED,IDLING
    ,'when pedal = 1 and turnkey = 1 and gas > 0');
$smachine->addTransition(IDLING,DRIVING
    ,'when gas > 0 and speed > 0');
$smachine->addTransition(DRIVING,IDLING
    ,'when brake = 1 and speed = 0');
$smachine->addTransition(IDLING,PARKED
    ,'when turnkey = 0 and speed = 0');

Таким образом, можно даже запрограммировать расширенные функции, например, что если у автомобиля кончится бензин или даже изменить значения.1017 * Хранит информацию в базе данных (необязательно).

Имеет пользовательский интерфейс (для тестирования), см. Изображение

state machine

Я также опубликовал статью об этом

https://medium.com/cook-php/creating-a-state-machine-using-php-ddef9395430e

1 голос
/ 29 марта 2015

Я написал конечный автомат для 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 require definitely246/state-machine
0 голосов
/ 15 октября 2016

Я создал Smalldb фреймворк для реализации слоя модели веб-приложения с использованием конечных автоматов.Он предназначен для работы непосредственно с базой данных SQL, где каждая строка таблицы SQL представляет экземпляр конечного автомата (поэтому конечные автоматы являются постоянными).

Он имеет управление доступом на основе ролей, поэтому вы можетеукажите в определении конечного автомата, какие переходы разрешены для каких пользователей (он также может иметь дело с владельцами экземпляра конечного автомата или компонентами более сложных объектов).

Для ускорения разработки Smalldb может загружать созданные диаграммы состояния в GraphMLс редактором yEd, так что вы можете нарисовать диаграмму состояний и затем напрямую использовать ее в своем приложении, а также в своей документации.Также в разработке находится нативный редактор (виджет jQuery + обертка рабочего стола).В целях отладки и онлайн-документации в приложении Smalldb может генерировать диаграммы состояний с использованием Graphviz.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...