🤖📘🍻 Hooray! After 3 years of work, we've finally released a new ebook on design patterns! Check it out »

Memento Design Pattern in PHP

In the Memento pattern a memento object will hold the state of another object.

In this example, the BookMark class is the "Memento", and holds the state of the BookReader class. The BookReader class would be the "Originator" in this example, as it had the original state. Client holds the BookMark object, and so is the "Caretaker".

The memento should be set up so that the caretaker can create, set, and get memento values for an originator. However, the caretaker itself can not access any of the values stored in the memento.

In my example I do this by having memento only allow calls to it's get and set functions in which it is passed a BookReader object. The BookMark can then get or set the titles or pages for a bookreader object it is passed. The downside of my implementation is that I have BookReader's get and set functions as public.

<?php

class BookReader {    
    private $title;   
    private $page;    
    function __construct($title_in, $page_in) {
      $this->setPage($page_in);
      $this->setTitle($title_in);
    }  
    public function getPage() {
      return $this->page;
    }      
    public function setPage($page_in) {
      $this->page = $page_in;
    }
    public function getTitle() {
      return $this->title;
    }      
    public function setTitle($title_in) {
      $this->title = $title_in;
    }
}

class BookMark {    
    private $title;    
    private $page;    
    function __construct(BookReader $bookReader) {
      $this->setPage($bookReader);
      $this->setTitle($bookReader);      
    }  
    public function getPage(BookReader $bookReader) {
      $bookReader->setPage($this->page);
    }  
    public function setPage(BookReader $bookReader) {
      $this->page = $bookReader->getPage();
    }    
    public function getTitle(BookReader $bookReader) {
      $bookReader->setTitle($this->title);
    }      
    public function setTitle(BookReader $bookReader) {
      $this->title = $bookReader->getTitle();
    }    
}

  // Client

  writeln('BEGIN TESTING MEMENTO PATTERN');
  writeln('');
 
  $bookReader = new BookReader('Core PHP Programming, Third Edition','103');
  $bookMark = new BookMark($bookReader);
 
  writeln('(at beginning) bookReader title: '.$bookReader->getTitle());
  writeln('(at beginning) bookReader page: '.$bookReader->getPage());
 
  $bookReader->setPage("104");
  $bookMark->setPage($bookReader);
  writeln('(one page later) bookReader page: '.$bookReader->getPage());  

  $bookReader->setPage('2005');  //oops! a typo
  writeln('(after typo) bookReader page: '.$bookReader->getPage());    
 
  $bookMark->getPage($bookReader);
  writeln('(back to one page later) bookReader page: '.$bookReader->getPage());    
  writeln('');

  writeln('END TESTING MEMENTO PATTERN');

  function writeln($line_in) {
    echo $line_in."<br/>";
  }

?> 

Output

BEGIN TESTING MEMENTO PATTERN

(at beginning) bookReader title: Core PHP Programming, Third Edition
(at beginning) bookReader page: 103
(one page later) bookReader page: 104
(after typo) bookReader page: 2005
(back to one page later) bookReader page: 104

END TESTING MEMENTO PATTERN

Code examples

More info, diagrams and examples of the Memento design pattern you can find on our new partner resource Refactoring.Guru.