Download the PHP package definitely246/state-machine without Composer
On this page you can find all versions of the php package definitely246/state-machine. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download definitely246/state-machine
More information about definitely246/state-machine
Files in definitely246/state-machine
Package state-machine
Short Description A finite state machine for php. Just playing around. Pull requests/forks welcome.
License MIT
Informations about the package state-machine
State Machine
All the things ... erm states
I know we just all adore computer science. It is the most coolest field ever, am I right? I sit here reminiscing about those glory days as a young undergrad computer science major. My favorite thing to do was draw finite state machines on a white board. I mean, Alan Turning be damned, finite state machines are awesome, am I right? ^_^
I wrote this state machine as an example in my Laravel Design Patterns book. The other ones I found for php were confusing to me. So I didn't want to use them. That might not be a great reason to write your own code, but why do you care? You get to use this awesome open source state machine with 100% test coverage that I wrote. Okay, enough kidding aside. Use this to create a state machine. Here is how you use it.
Install
Using composer you can install state machine.
Quickstart Example
State Pattern - A Clean Approach & Alternative to State Machine
First let's consider the state pattern. It is a very nice pattern to use. A quick way to get started with states in your objects is by using the StateMachine\Stateful
trait. This injects State pattern functionality into your class. This approach offers a clean way to add states and a context to your php classes.
Now that you've defined those classes, you can start to call the flipSwitch event on light. It will use the initial state to determine all the available events for this state machine. You should be careful to define the same events across the board. You can implement an interfae to help with that.
State Machine - A different approach
A state machine can be wrapped around some context object. When transitions are called, a handler class receives the event and is asked to handle it accordingly. Below is a transition handler class, Event1ChangedState1ToState2
. It is called whenever event1 is triggered from state1 and is attempting to change state to state2. The second transition class, Event1ChangdState2ToState1
, handles transitioning state2 to state1 when event1 was called.
Next we definte transitions for this finite state machine.
Vending Machine Example
Think about a vending machine that allows you buy candy, snacks, soda pop. If you try to purchase a candy bar without paying for it, the machine shouldn't disperse anything right? We can map out the transisitions for a simple vending machine. Because we are not evil we'll add in a refund transition too. This will allow people who inserted their money change their minds and get their money back without purchasing anything.
Note This particular example is non-deterministic (two outcomes for purchase event). If you don't have a problem with it, I got no problem with it either. ^_^
Transitions
To use StateMachine
you'll need a list of transistions. Each transistion needs an event, from state and to state.. These 3 things make a transition. Now we convert this diagram into an event table of transitions using the fsm diagram above.
Take a good long stare at the transitions above. I think we got them all. You can step through them. Now that we have our transitions defined, we need to create a finite state machine that uses these transitions.
Transition Event Handlers
We have created 5 transitions for this finite state machine. Out of the box every transition requires a handler class. Let's define handler class for our first event insert
which changes the state from idle to has money. The class name we need to create is InsertChangesIdleToHasMoney
. It looks like this.
Context
You might be wondering, what is this $context thing? It happens to be a very generic storage object. We can set our own context object on our finite state machine if we'd like. The context is passed to all transition events. It's a way for states to communiate changes with each other. It is the 2nd parameter of the constructor.
If you are using an Eloquent model (from Laravel), you might do something like this:
Object Factory
But wait, that's not all. There is also 3rd parameter on FSM too. In fact, let's show the method signature for the FSM constructor. You can see below that you can apply your own ObjectFactory
object to finite state machine. This factory is what creates new transition handler objects. If you'd like to change the way handler classes are named, then you should override this factory.
If you pass a string to $factory
it uses that as the namespace for transition event classes.
This lets us group our handlers into a single namespace. Now the StateMachine\Exceptions\TransitionHandlerNotFound
exception should be telling us that it cannot find \MyNamespaceToTransitionHandlerEvents\InsertChangesIdleToHasMoney
. Neat right? If you need more control, such as turning off $strictMode
or changing how handler classes are created then you can use your own ObjectFactory
and provide that factory to your finite state machine constructor.
If you pass $strictMode = false
to the ObjectFactory
the anytime transition handler classes are not found, the object factory returns a StateMachine\DefaultTransitionHandler
instead.
If ObjectFactory
has strictMode = true
then you must write a handler for every event transition, even if they are just blank. I recommend using $strictMode = true
because it lets you know quickly which transistion event handler classes you need to create and allows you to tap into the finite state machine's context.
Whiny mode
If you don't want exceptions for invalid transition event requests then turn whiny mode off. Note this makes it harder to troubleshoot though.
Canceling State Transition
You can cancel event transitions in the handle()
method using an exception.
With the above changes to our event transition handler we will get the following output
Triggering Another State Transition
You can also trigger events off another state. This is complex and probably should be avoided. However, if you find yourself needing to trigger an event inside of another event, then you can use TriggerTransitionEvent
.
Now triggering insert inside of has money state actually ends up triggering refund
Finite State Machine Stopped
You can see if the fsm is stopped at anytime. Once in stopped all events triggered will fail. If whiney mode is true then you will get a StateMachineIsStopped
exception, otherwise you'll get a false.
Licence
This is a MIT licence. That means you can pretty much use it for any of your cool projects.
Contributions
If you want to make changes, please fork this repository and make a pull request. Ensure that you have unit tests written for any new functionality and they are passing in phpunit. I use mockery for mocking. Also, if you add responsibilities to classes, you might consider new classes. The FSM class is already doing a lot.
Did you make it this far? You made it to the bottom of the page? Well, dang. You probably did a lot better in your computer science courses than me. Laters, amigos. Have a nice day. ^_^