start - Estructura de la máquina de estado de PHP
php<?= (7)
He creado el framework Smalldb para implementar la capa de modelo de una aplicación web utilizando máquinas de estado. Está diseñado para trabajar directamente en la base de datos SQL, donde cada fila de la tabla SQL representa una instancia de una máquina de estado (por lo que las máquinas de estado son persistentes).
Tiene control de acceso basado en roles, por lo que puede especificar en la definición de la máquina de estado qué transiciones se permiten a qué usuarios (también puede tratar con los propietarios de la instancia de la máquina de estado o los componentes de entidades más complejas).
Para acelerar el desarrollo, Smalldb puede cargar diagramas de estado en GraphML creados con el editor yEd, para que pueda dibujar una gráfica de estado y luego utilizarla directamente en su aplicación y en su documentación. También hay un editor nativo (jQuery widget + desktop wrapper) en desarrollo. Para propósitos de depuración y documentación en línea dentro de la aplicación, Smalldb puede generar diagramas de estado usando Graphviz.
Dudo que exista un marco de máquina de estado como https://github.com/pluginaweek/state_machine para PHP.
Tuve que definir muchas cláusulas lógicas if-else, y me gustaría algo para ayudar a hacerlo más divertido simplemente definiendo:
- Condición requerida para la transición
- Estado después de la transición
Entonces esto puede ser reutilizado para verificar si las condiciones coinciden o no, por ejemplo
$customer->transition(''platinum'');
Espero que esta línea de código compruebe implícitamente si el cliente puede hacer la transición o no. O compruebe explícitamente por:
$customer->canTransitTo(''platinum'');
Gracias de antemano, noomz
He escrito una máquina de estado para php. Estoy seguro de que has descubierto una solución hace mucho tiempo para esto. Pero para las personas que visitan esta página, pueden probar esta máquina de estados.
https://github.com/definitely246/state-machine
Para usarlo, se definen los controladores de eventos de transición como clases. Entonces necesitas definir transiciones. La máquina de estados finitos puede configurarse para hacer otras cosas, pero aquí están los conceptos básicos.
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++;
}
}
Luego puede definir las transiciones que cambian de estado cuando se activa un evento.
$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''
Se puede instalar con el compositor.
composer require definitely246/state-machine
He estado trabajando en una simple biblioteca de máquinas de estados finitos de PHP, algo similar a los rieles state_machine. El código está aquí: https://github.com/chriswoodford/techne/tree/v0.1
Un ejemplo de automóvil, similar a la respuesta seleccionada (arriba) se vería así:
Inicialización
$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'');
Uso
$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"
Carece de una interfaz definida explícitamente que, dado que usa el método mágico __call () para aceptar mensajes, se puede resolver fácilmente con un adapter .
He usado este https://github.com/yohang/Finite que es bastante poderoso, sin embargo, los documentos no son tan detallados. Si está familiarizado con las máquinas de estado, entonces no debería tener ningún problema.
No conozco un marco como este (lo que no significa que no exista). Pero aunque no está tan lleno de funciones como el marco vinculado, el patrón de estado es bastante simple de implementar. Considere esta implementación ingenua a continuación:
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;
}
}
Después de definir los estados, solo tienes que aplicarlos a tu objeto principal:
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();
}
}
Y luego puedes hacer
$car = new Car;
try {
$car->moveForward(); // throws Exception
} catch(LogicException $e) {
echo $e->getMessage();
}
$car = new Car;
$car->startEngine();
$car->moveForward();
Para reducir las declaraciones if / else demasiado grandes, esto debería ser suficiente. Tenga en cuenta que devolver una nueva instancia de estado en cada transición es algo ineficiente. Como dije, es una implementación ingenua para ilustrar el punto.
Para el registro, escribo (otra) máquina de estados
https://github.com/EFTEC/StateMachineOne
Sin embargo, se basa en la automatización y no en el evento (sin embargo, es posible utilizar un campo como evento). La transición de estado se desencadena por valores, manualmente o por código.
Por ejemplo, el ejemplo de estacionamiento:
donde pedal, llave en mano, gas, velocidad y freno son campos definidos y controlados por código.
$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'');
Por lo tanto, incluso es posible programar funciones avanzadas como, por ejemplo, si el automóvil se queda sin combustible o incluso modificar los valores.
caracteristicas:
- Almacena la información en la base de datos (opcional).
- Tiene una interfaz de usuario (para pruebas) ver imagen
También publiqué un artículo al respecto.
https://medium.com/cook-php/creating-a-state-machine-using-php-ddef9395430e