Use the Memento Design Pattern | PHP Code Examples in 2023

Last Updated on

CraftyTechie is reader-supported. When you buy through links on our site, we may earn an affiliate commission.

Using the Memento Pattern in PHP

The memento pattern is a behavioral design pattern which lets you save and restore an object to its previous state without compromising its privacy.

Article Highlights

  • The memento pattern delegates creating a snapshot to the original object while keeping the state in a memento object.
  • Benefit –   Doesn’t violate the data encapsulation of the original objects.
  • Con –        Creating memento objects too often can consume much memory.

Memento Design Pattern PHP Code Example

<?php

interface Originator {

    public function createSnapshot();

}
// The originator class
class WhiteBoard implements Originator {

    private $fontSize;
    private $fontFamily;
    private $canvasSize;
    private $canvasColor;
    private $output;

    //More fields...

    function __construct($fontSize, $fontFamily, $canvasSize, $canvasColor, $output) {
        $this->fontSize = $fontSize;
        $this->fontFamily = $fontFamily;
        $this->canvasSize = $canvasSize;
        $this->canvasColor = $canvasColor;
        $this->output = $output;
    }

    function setFontSize($fontSize) {
        $this->fontSize = $fontSize;
    }

    function setFontFamily($fontFamily) {
        $this->fontFamily = $fontFamily;
    }

    function setCanvasSize($canvasSize) {
        $this->canvasSize = $canvasSize;
    }

    function setCanvasColor($canvasColor) {
        $this->canvasColor = $canvasColor;
    }

    function setOutput($output) {
        $this->output = $output;
    }

    function getStateInfo() {
        return "\nFont Size: ".$this->fontSize."\nFont Family: ".$this->fontFamily.
               "\nCanvas Size: ".$this->canvasSize."\nCanvas Color: ".$this->canvasColor."\nOutput Format: ".$this->output."\n\n";
    }
    
    // Saves the state to the momento
    function createSnapshot() {

        //Passes reference to itself and fields.
        return new SnapShot($this,  $this->fontSize,  $this->fontFamily,  $this->canvasSize,  $this->canvasColor,  $this->output);
    }

    //More methods....
}

interface Memento {

    public function restore();
}

// The memento class
class SnapShot implements Memento {

    private $whiteboard;
    private $fontSize;
    private $fontFamily;
    private $canvasSize;
    private $canvasColor;
    private $output;

    function __construct($whiteboard, $fontSize, $fontFamily, $canvasSize, $canvasColor, $output) {
        $this->whiteboard = $whiteboard;
        $this->fontSize = $fontSize;
        $this->fontFamily = $fontFamily;
        $this->canvasSize = $canvasSize;
        $this->canvasColor = $canvasColor;
        $this->output = $output;
    }

    //Restores the originator state by passing the stored set of fields to the setter functions.
    function restore() {
        $this->whiteboard->setFontSize($this->fontSize);
        $this->whiteboard->setFontFamily($this->fontFamily);
        $this->whiteboard->setCanvasSize($this->canvasSize);
        $this->whiteboard->setCanvasColor($this->canvasColor);
        $this->whiteboard->setOutput($this->output);
    }
}

//The UndoCommand act as a caretaker.
class UndoCommand {

    private $memento;

    function createSnapshot($whiteboard) {
        $this->memento = $whiteboard->createSnapshot();
    }

    function undo() {
        //If memento exists
        if($this->memento) {
            $this->memento->restore();
        }

    }
}

function main() {
    
    $whiteboard = new Whiteboard('20px', 'Arial', '1000px', 'White', 'png');
    $undoCommand = new UndoCommand();

    echo "Initial State: ".$whiteboard->getStateInfo();

    //Creates snapshot of the initial state
    $undoCommand->createSnapshot($whiteboard);

    //New state
    $whiteboard->setFontSize('11px');
    $whiteboard->setFontFamily('Times new roman');
    $whiteboard->setCanvasSize('800px');
    $whiteboard->setCanvasColor('Brown');
    $whiteboard->setOutput('jpeg');

    echo "New State: ".$whiteboard->getStateInfo();

    //Reverts whiteboard to initial state
    $undoCommand->undo();


    echo "Reverted State: ".$whiteboard->getStateInfo();
}

/*
OUTPUT 

Initial State: 
Font Size: 20px
Font Family: Arial
Canvas Size: 1000px
Canvas Color: White
Output Format: png

New State: 
Font Size: 11px
Font Family: Times new roman
Canvas Size: 800px
Canvas Color: Brown
Output Format: jpeg

Reverted State: 
Font Size: 20px
Font Family: Arial
Canvas Size: 1000px
Canvas Color: White
Output Format: png
*/
?>
Memento Pattern PHP

Table of Contents

What is the Memento Pattern

“The memento pattern is a behavioral design pattern which lets you save and restore an object to its previous state without compromising its privacy.”

Memento Pattern PHP

Memento Pattern Example

Imagine that we are building a whiteboard tool. The whiteboard has several options, including font size & family, canvas size & colour and output format. Users can take a snapshot of their whiteboard and can undo it.

save-and-restore

The application saves these snapshots in storage and retrieves them when a user chooses to revert from the current state. 

An easy way to implement this functionality is to loop through the object fields and copy them over to the storage. This approach sounds straightforward and may work if the object provides a way to access all its fields, but there are many concerns from a design perspective.

Problem 🙁

Single responsibility principle

“A class should have one and only one responsibility.”, states the single responsibility principle. Merging the save & retrieve methods with an unrelated set of methods increases the cohesion of a class. A highly cohesive module is more generalised with more than one aspect of the operation.

What’s the problem with high cohesion? The issue comes when parts of your application change. If a module does much more than it is supposed to, this change will likely affect it. We want to limit the scope of changes in a system to avoid an avalanche effect.

So, in terms of this principle, the state management should sit in a separate module than co-existing with other unrelated sets of operations.

Open-closed principle

“A class should be closed for modification but open for extension.”, states the open/closed principle. Suppose we refactor the Whiteboard class in the future, adding or removing fields. Such changes will force us to modify the methods which save and restores the state. Adding more classes to the design will also affect the whole system.

Moreover, using a direct approach tends to use concrete classes rather than abstractions, which is another red flag regarding the degree of the system’s flexibility. 

Data encapsulation

Data hiding or encapsulation is important in object-oriented programming (OOP). An object has control over what data to hide and what to expose. Usually, there is a mix of private and public fields and methods in a class. A class defines an interface for external entities.

An interface typically doesn’t reveal the internal details but provides a point of interaction for external objects and entities. 

Generally speaking, from a security perspective, a process or entity should have only the bare minimum privileges to perform intended functions. This statement is a fundamental principle called the principle of least privilege. So exposing data of a class is a negation of this principle.

The direct approach we have been discussing lately is only possible if the class is public; everyone can access anything. This behaviour is undesirable because classes, as we have said, already have private data too.

Solution 🙂

Memento

So, what is a Memento? In literary terms, a memento is a reminder of an important event that has occurred in the past. Notes, photographs or anything tangible that helps recall a past event can be called memento(s).

The idea is pretty much identical in object-oriented designs, except that we deal with classes and objects. So, a memento is an object which stores the state of an object. 

 But why memento?

  • Memento separates the saved state from the original object and helps maintain cohesion.
  • Memento pattern delegates the responsibility of creating a snapshot to the original object. Since the object has full access to its data, it takes the encapsulation concern out of the equation.
  • Memento exposes a limited interface to external entities, thus not compromising private fields. 
  • The original object has full access to memento data and uses it to restore its previous state.

So, the memento pattern addresses almost every issue identified above. Let’s explore the memento pattern more to understand the complete solution.

Anatomy of memento pattern

An Originator is an original object which creates snapshots. The originator creates snapshots and stores them in memento objects.

originator-memento

Caretaker objects are another set of classes that can store memento objects and interact with them via their limited interface. The purpose is usually to store them or dispatch commands on them without peeking inside them.

originator-memento-caretaker

Benefits of the Memento Pattern

  • Maintain original class cohesion by keeping the state in a memento.
  • Creates a snapshot of the object without compromising data encapsulation.
  • Exposes a simple interface for creating a copy of an object’s state.

Complete Architecture | Memento Pattern in PHP

Memento Pattern PHP

Memento Pattern PHP Pseudocode Example

<?php

interface Originator {

    public function createSnapshot();

}
// The originator class
class WhiteBoard implements Originator {

    private $fontSize;
    private $fontFamily;
    private $canvasSize;
    private $canvasColor;
    private $output;

    //More fields...

    function __construct($fontSize, $fontFamily, $canvasSize, $canvasColor, $output) {
        $this->fontSize = $fontSize;
        $this->fontFamily = $fontFamily;
        $this->canvasSize = $canvasSize;
        $this->canvasColor = $canvasColor;
        $this->output = $output;
    }

    function setFontSize($fontSize) {
        $this->fontSize = $fontSize;
    }

    function setFontFamily($fontFamily) {
        $this->fontFamily = $fontFamily;
    }

    function setCanvasSize($canvasSize) {
        $this->canvasSize = $canvasSize;
    }

    function setCanvasColor($canvasColor) {
        $this->canvasColor = $canvasColor;
    }

    function setOutput($output) {
        $this->output = $output;
    }

    function getStateInfo() {
        return "\nFont Size: ".$this->fontSize."\nFont Family: ".$this->fontFamily.
               "\nCanvas Size: ".$this->canvasSize."\nCanvas Color: ".$this->canvasColor."\nOutput Format: ".$this->output."\n\n";
    }
    
    // Saves the state to the momento
    function createSnapshot() {

        //Passes reference to itself and fields.
        return new SnapShot($this,  $this->fontSize,  $this->fontFamily,  $this->canvasSize,  $this->canvasColor,  $this->output);
    }

    //More methods....
}

interface Memento {

    public function restore();
}

// The memento class
class SnapShot implements Memento {

    private $whiteboard;
    private $fontSize;
    private $fontFamily;
    private $canvasSize;
    private $canvasColor;
    private $output;

    function __construct($whiteboard, $fontSize, $fontFamily, $canvasSize, $canvasColor, $output) {
        $this->whiteboard = $whiteboard;
        $this->fontSize = $fontSize;
        $this->fontFamily = $fontFamily;
        $this->canvasSize = $canvasSize;
        $this->canvasColor = $canvasColor;
        $this->output = $output;
    }

    //Restores the originator state by passing the stored set of fields to the setter functions.
    function restore() {
        $this->whiteboard->setFontSize($this->fontSize);
        $this->whiteboard->setFontFamily($this->fontFamily);
        $this->whiteboard->setCanvasSize($this->canvasSize);
        $this->whiteboard->setCanvasColor($this->canvasColor);
        $this->whiteboard->setOutput($this->output);
    }
}

//The UndoCommand act as a caretaker.
class UndoCommand {

    private $memento;

    function createSnapshot($whiteboard) {
        $this->memento = $whiteboard->createSnapshot();
    }

    function undo() {
        //If memento exists
        if($this->memento) {
            $this->memento->restore();
        }

    }
}

function main() {
    
    $whiteboard = new Whiteboard('20px', 'Arial', '1000px', 'White', 'png');
    $undoCommand = new UndoCommand();

    echo "Initial State: ".$whiteboard->getStateInfo();

    //Creates snapshot of the initial state
    $undoCommand->createSnapshot($whiteboard);

    //New state
    $whiteboard->setFontSize('11px');
    $whiteboard->setFontFamily('Times new roman');
    $whiteboard->setCanvasSize('800px');
    $whiteboard->setCanvasColor('Brown');
    $whiteboard->setOutput('jpeg');

    echo "New State: ".$whiteboard->getStateInfo();

    //Reverts whiteboard to initial state
    $undoCommand->undo();


    echo "Reverted State: ".$whiteboard->getStateInfo();
}

/*
OUTPUT 

Initial State: 
Font Size: 20px
Font Family: Arial
Canvas Size: 1000px
Canvas Color: White
Output Format: png

New State: 
Font Size: 11px
Font Family: Times new roman
Canvas Size: 800px
Canvas Color: Brown
Output Format: jpeg

Reverted State: 
Font Size: 20px
Font Family: Arial
Canvas Size: 1000px
Canvas Color: White
Output Format: png
*/
?>

Pros and Cons of the Memento Pattern in PHP

ProsCons
Satisfied single responsibility principle by keeping saved state separate from the original object.Creating memento objects too often can consume a large chunk of memory.
Doesn’t violate the data encapsulation of the original objects.No easy way of marking and deleting obsolete memento objects.
Provides an easy interface for creating snapshots.

Where is the Memento Pattern Used

  • To implement state retention and restoration in stateful components of a program.
  • Text editors, IDEs and version controls can use the memento pattern.

What is the Memento Pattern

The memento pattern is a behavioral design pattern which lets you save and restore an object to its previous state without compromising its privacy.

Using the Memento Pattern in PHP Today

That’s all about the memento pattern. Let’s quickly sum up what we have learned thus far. The memento pattern is a behavioral design pattern which lets you save and restore an object to its previous state without compromising its privacy.

The memento pattern has three main components: Originator, which creates its state snapshot. Memento saves the state and helps restores it. The Caretaker stores the memento objects and uses their limited public interface for interaction.

This article features a whiteboard application with several options that represent its state. The goal is to create an undo function for it so that a user can revert to the previous state. One direct way is to loop through the object’s fields and copy them individually. Although this approach is easy, it has some flaws, including the issue that it compromises the data encapsulation of the original object.

That’s why we use the memento pattern, which delegates the snapshot creation to the originator object so that its data encapsulation is not violated. The memento saves the state to improve the cohesion of the originator class. The process of creating a snapshot thus becomes quite convenient with this pattern.

That’s all. See you in another design pattern article.

Books on Design Patterns

Want to learn more about Design Patterns? There are many great resources online. We recommend the following books for your collection as they both can teach you the theoretical and the application of using design patterns in your day-to-day programming. Feel free to use the following Amazon affiliate links if you’d like to purchase them and a way to support our efforts.

Design Patterns: Elements of Reusable Object-Oriented Software

Design Patterns: Elements of Reusable Object-Oriented Software book

This is the book that started it all. I believe that every programmer should have a referenced copy to this book at some point in their career. There have been many updates and excellent newer content through the years, but this is a classic. It still stands the test of time and is just as relevant for today as it was in the original printing in the 90s.

Check it out on amazon

Learning PHP Design Patterns

This is an excellent book to go beyond the theory and apply it to writing good PHP code. Learning PHP Design Patterns is published by the popular O’Reilly media company. O’Reilly consistently publishes some of the most useful reference material related to software development. They are known to provide materials that thoroughly cover a topic in a way that is simple to understand. I recommend this book to every PHP developer.

Check it out on amazon

Want to see our full review of books on design patterns? Read our huge review article on over 15 design pattern books.

Design Patterns in PHP Learning Series.

This article is part of our series of design patterns in PHP. We are going through all of the patterns and showing how they can help you build better applications. Browse through our full list of patterns below.

Did you find this article helpful?

Join the best weekly newsletter where I deliver content on building better web applications. I curate the best tips, strategies, news & resources to help you develop highly-scalable and results-driven applications.

Build Better Web Apps

I hope you're enjoying this article.

Get the best content on building better web apps delivered to you.