The state pattern is a behavioural pattern which allows an object to alter its behaviour when its internal state changes. The pattern is a well known and commonly used software design pattern. The pattern is closely related to state machines and finite state machines.

For this review, I’ve implemented a pseudo shipping status library which invokes different actions based on the state of the order. As you can clearly see in the implementation below, objects are altering their behaviours when internal state changes are made. Source code is below.

Implementation Code



require_once '../vendor/FigStandards/autoload.php';

//Load Dependencies 
$loader = new figStandards\Psr4AutoloaderClass;
$loader->register();
$loader->addNamespace('stateMachine', 'stateMachine');

class client {

    public function __construct() {

        /**
         * The client code.
         */
        echo "

Pending Order

"; $order = new stateMachine\orderStatus(); $order->action(new stateMachine\orderItem("Some Order", "With Products")); echo "

----------------------------
"; echo "

Assigned Order

"; $order->setContext(new stateMachine\assigned()); $order->action(new stateMachine\orderItem("Another Order", "More Products")); echo "

---------------------------
"; echo "

Shipped Order

"; $order->setContext(new stateMachine\shipped()); $order->action(new stateMachine\orderItem("Different Order", "Even More Products")); } } new client();

OrderItem Class


namespace stateMachine;

class order {

    private $id;
    private $orderItem;
    private $details;

    /**
     * Data object for pseudo order
     * @param type $id
     * @param type $orderItem
     * @param type $details
     */
    public function __construct($id, $ErrorTitle, $stackTrace) {
        foreach (func_get_args() as $k => $v) {
            $this->{$k} = $v;
        }
    }

}


OrderStatus Class



namespace stateMachine;

class OrderStatus {

    private $state;
    private $error;

    /**
     * Instantiate the initial vector
     */
    public function __construct() {
        $this->setContext(new Pending());
    }

    /**
     * Sets the object context
     * @param \stateMachine\State $state
     * @return $this
     */
    public function setContext(State $state) {
        print("

Context: " . get_class($state) . ".

"); $this->state = $state; $this->state->setContext($this); return $this; } /** * actions the order * @param type $error */ public function action($order) { $this->state->action(); } }

Pending Class



namespace stateMachine;

class Pending extends State {

    /**
     *  {@inheritdoc}
     */
    public function action() {
        echo "Emailer::SendToAll('Thank you for your order.');";
        
    }

}



Assigned Class



namespace stateMachine;

class Assigned extends State {

    /**
     *  {@inheritdoc}
     */
    public function action() {
        echo "Shipping::Assign_Consignment('To a Carrier');";
       
    }

}


Shipped Class



namespace stateMachine;

class Shipped extends State
{
    /**
     *  {@inheritdoc}
     */
    public function action()
    {
        echo "Emailer::SendToCustomer('Order Dispatched');";
        echo "Shipping::Carrier('dispatched')";
    }

}

State Class



namespace stateMachine;

abstract class State
{
    /**
     * @var Holds the object context
     */
    protected $context;

    /**
     * Sets the context, then encapsulates itself for the purpose of method chaining
     * @param type $context
     * @return $this
     */
    public function setContext($context)
    {
        $this->context = $context;
        return $this;
    }

    /**
     * Invokes the action response
     */
    abstract public function action();
}