User Tools

Site Tools


php:state

STATE PATTERN

30.03.2010

The State pattern allows an object to change its behavior when its internal state changes. Basically the states are kept in a separate object that encapsulates the state-related behavior. The switch constructions are often candidates for this pattern.

 State Pattern Diagram

Participants:

  • Context: defines an interface for Clients and maintains a State object internally.
  • State: defines an interface for the state-related behavior and often for transitions.
  • ConcreteState (more than one class): implements a particular behavior and set of valid transitions.

The State pattern does not specify where the state transitions will be defined. The choices are two: the context object, or each individual State derived class. The advantage of the later option is ease of adding new State derived classes. The disadvantage is each State derived class has knowledge of (coupling to) its siblings, which introduces dependencies between subclasses.

We get the example of a Printer with 4 identified states: ready, print starting, printing (in progress), print ending.
Each state class will have an action() method and an (optionally) display_state() method (used to better debug the operations).
States classes will look as:

// State interface here
interface PrinterState {
    public function display_state();
    public function action();
 
}
 
// Concrete States classes follow
class StateReady implements PrinterState {
    public function action() {
        echo "Printer is ready.\n";
        return new StatePrintStart;
    }
 
    public function display_state() { echo get_class($this)."->"; }
}
 
class StatePrintStart implements PrinterState {
    public function action() {
        echo "The print is starting.\n";
        return new StatePrinting;    
    }
 
    public function display_state() { echo get_class($this)."->"; }
}
 
class StatePrinting implements PrinterState {
 
    public function action() {
        echo "Printer is printing nicely.\n";
        return new StatePrintEnd;
    }
 
    public function display_state() { echo get_class($this)."->"; }
}
 
class StatePrintEnd implements PrinterState {
 
    public function action() {
        echo "Printer has finish its job.\n";
        return new StateReady;
    }
 
    public function display_state() { echo get_class($this)."->"; }
}

After this, the interface class:

class Printer {
    protected $_printerstate;
 
    /**
     * @param State $initialState   the state at the start
     */
    public function __construct(PrinterState $initialState) {
        $this->_printerstate = $initialState;
    }
 
    public function run() {
        $this->_printerstate->display_state(); // just for displaying purposes
        $this->_printerstate = $this->_printerstate->action(); // each action returns next possible state
    }
 
    public function cancel() {
        // simplified example
        // this will call the end state no matter what and after end action, prepare again the printer
        $endstate = new StatePrintEnd;
        $this->_printerstate = $endstate->action();
    }
}

Then run the code:

$printer = new Printer(new StateReady);
 
echo "---------------------- \n";
$printer->run(); // the printer becomes ready
echo "---------------------- \n";
$printer->cancel(); // here we cancel
echo "---------------------- \n";
$printer->run(); // return and retry again
echo "---------------------- \n";
$printer->run();
echo "---------------------- \n";
$printer->run();
echo "---------------------- \n";
$printer->run();
echo "---------------------- \n";

Result for above code is:

...$> php state_pattern.php 
---------------------- 
StateReady->Printer is ready.
---------------------- 
Printer has finish its job.
---------------------- 
StateReady->Printer is ready.
---------------------- 
StatePrintStart->The print is starting.
---------------------- 
StatePrinting->Printer is printing nicely.
---------------------- 
StatePrintEnd->Printer has finish its job.
---------------------- 

References:

Robot example
Giorgio Sironi example
Page about State Pattern

php/state.txt · Last modified: 2013/03/16 17:40 (external edit)