State Design Pattern in PHP

In the State Pattern a class will change it's behavior when circumstances change.

In this example, the BookContext class holds an implementation of the BookTitleStateInterface, starting with BookTitleStateStars. BookTitleStateStars and BookTitleStateExclaim will then replace each other in BookContext depending on how many times they are called.

<?php

class BookContext {
    private $book = NULL;
    private $bookTitleState = NULL; 
    //bookList is not instantiated at construct time
    public function __construct($book_in) {
      $this->book = $book_in;
      $this->setTitleState(new BookTitleStateStars());
    }
    public function getBookTitle() {
      return $this->bookTitleState->showTitle($this);
    }  
    public function getBook() {
      return $this->book;
    }
    public function setTitleState($titleState_in) {
      $this->bookTitleState = $titleState_in;
    }
}

interface BookTitleStateInterface {
    public function showTitle($context_in);
}
 
class BookTitleStateExclaim implements BookTitleStateInterface {
    private $titleCount = 0; 
    public function showTitle($context_in) {
      $title = $context_in->getBook()->getTitle();
      $this->titleCount++;
      $context_in->setTitleState(new BookTitleStateStars());
      return Str_replace(' ','!',$title);
    }
}

class BookTitleStateStars implements BookTitleStateInterface {
    private $titleCount = 0; 
    public function showTitle($context_in) {
      $title = $context_in->getBook()->getTitle();
      $this->titleCount++;
      if (1 < $this->titleCount) {
        $context_in->setTitleState(new BookTitleStateExclaim); 
      }
      return Str_replace(' ','*',$title);
    }
}

class Book {
    private $author;
    private $title;
    function __construct($title_in, $author_in) {
      $this->author = $author_in;
      $this->title  = $title_in;
    }
    function getAuthor() {return $this->author;}
    function getTitle() {return $this->title;}
    function getAuthorAndTitle() {
      return $this->getTitle() . ' by ' . $this->getAuthor();
    }
}

  writeln('BEGIN TESTING STATE PATTERN');
  writeln('');
 
  $book = new Book('PHP for Cats','Larry Truett');;
  $context = new bookContext($book);
 
  writeln('test 1 - show name');
  writeln($context->getBookTitle());
  writeln('');

  writeln('test 2 - show name');
  writeln($context->getBookTitle());
  writeln('');
 
  writeln('test 3 - show name');
  writeln($context->getBookTitle());
  writeln('');
 
  writeln('test 4 - show name');
  writeln($context->getBookTitle());
  writeln('');

  writeln('END TESTING STATE PATTERN');
 
  function writeln($line_in) {
    echo $line_in."<br/>";
  }

?>

Output

BEGIN TESTING STATE PATTERN

test 1 - show name
PHP*for*Cats

test 2 - show name
PHP*for*Cats

test 3 - show name
PHP!for!Cats

test 4 - show name
PHP*for*Cats

END TESTING STATE PATTERN

Code examples