manuel
Posted on September 28, 2017
The State pattern is excellent for making the behavior of an object dependent on its state. In my example, it is an elevator that can have the following states:
- Open (Open)
- Closed (Close)
- In Motion (Move)
- Stand (Stop)
From this, the following interface can be derived
<?php
namespace Elevator;
interface ElevatorStateInterface
{
public function open();
public function close();
public function move();
public function stop();
}
Now we need a class ElevatorState that implements the interface
<?php
namespace Elevator;
class ElevatorState implements ElevatorStateInterface
{
public function close()
{
throw new \Elevator\Exception\IllegalStateTransitionException();
}
public function move()
{
throw new \Elevator\Exception\IllegalStateTransitionException();
}
public function open()
{
throw new \Elevator\Exception\IllegalStateTransitionException();
}
public function stop()
{
throw new \Elevator\Exception\IllegalStateTransitionException();
}
}
By default, all methods throw an exception. In my case it is an IllegalStateTransitionException which inherits from LogicException.
Now we can implement the individual states. In this example, the Move state.
<?php
namespace Elevator\State;
class Move extends \Elevator\ElevatorState
{
public function move()
{
return new Move();
}
public function stop()
{
return new Stop();
}
}
As you can see, not all methods are implemented from ElevatorState.
Exactly this, which are not allowed for the current state.
The class Elevator
<?php
namespace Elevator;
class Elevator
{
private $state;
function getState()
{
return $this->state;
}
function setState(ElevatorStateInterface $state)
{
$this->state = $state;
print "set state to : " . get_class($state) . PHP_EOL;
}
public function __construct()
{
$this->setState(new \Elevator\State\Stop());
}
public function isOpen()
{
return $this->state instanceof \Elevator\State\Open;
}
public function open()
{
$this->setState($this->state->open());
}
public function close()
{
$this->setState($this->state->close());
}
public function move()
{
$this->setState($this->state->move());
}
public function stop()
{
$this->setState($this->state->stop());
}
}
If you call the class with
<?php
$elevator = new Elevator\Elevator();
it gets the state Stop by the constructor. This means we can switch from this state to the Open state.
<?php
$elevator->open();
Now, I try this
<?php
$elevator->move();
An error will happen
PHP Fatal error: Uncaught Elevator\Exception\IllegalStateTransitionException
because the door must first be closed.
<?php
$elevator->close();
The complete source of this example is available on GitHub.
Posted on September 28, 2017
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.