Explore the Memento Design Pattern in PHP, a behavioral pattern that captures and restores an object's state without violating encapsulation. Learn how to implement it with examples and use cases.
The Memento Pattern is a behavioral design pattern that provides the ability to restore an object to its previous state. This pattern is particularly useful for implementing features like undo mechanisms, checkpoints in games, or any scenario where you need to revert an object to a previous state without exposing its internal structure.
The primary intent of the Memento Pattern is to capture and externalize an object’s internal state without violating encapsulation, allowing it to be restored later. This is achieved by storing the state in a separate object, known as the memento, which can be used to restore the original object to its previous state.
Use the Memento Pattern when:
Let’s explore how to implement the Memento Pattern in PHP by creating a simple text editor application that supports undo functionality.
The TextEditor class acts as the originator. It maintains the current text and can create and restore mementos.
1<?php
2
3class TextEditor {
4 private $text = '';
5
6 public function write($words) {
7 $this->text .= $words;
8 }
9
10 public function getText() {
11 return $this->text;
12 }
13
14 public function save() {
15 return new TextEditorMemento($this->text);
16 }
17
18 public function restore(TextEditorMemento $memento) {
19 $this->text = $memento->getText();
20 }
21}
The TextEditorMemento class stores the state of the TextEditor.
1<?php
2
3class TextEditorMemento {
4 private $text;
5
6 public function __construct($text) {
7 $this->text = $text;
8 }
9
10 public function getText() {
11 return $this->text;
12 }
13}
The EditorHistory class acts as the caretaker, managing the mementos.
1<?php
2
3class EditorHistory {
4 private $history = [];
5
6 public function save(TextEditorMemento $memento) {
7 $this->history[] = $memento;
8 }
9
10 public function undo() {
11 if (!empty($this->history)) {
12 return array_pop($this->history);
13 }
14 return null;
15 }
16}
Let’s see how these classes work together to provide undo functionality.
1<?php
2
3$editor = new TextEditor();
4$history = new EditorHistory();
5
6$editor->write("Hello, ");
7$history->save($editor->save());
8
9$editor->write("World!");
10$history->save($editor->save());
11
12echo "Current Text: " . $editor->getText() . "\n"; // Output: Hello, World!
13
14$editor->restore($history->undo());
15echo "After Undo: " . $editor->getText() . "\n"; // Output: Hello,
16
17$editor->restore($history->undo());
18echo "After Undo: " . $editor->getText() . "\n"; // Output: (empty string)
To better understand the interactions between the components of the Memento Pattern, let’s visualize it using a class diagram.
classDiagram
class TextEditor {
- text: string
+ write(words: string)
+ getText(): string
+ save(): TextEditorMemento
+ restore(memento: TextEditorMemento)
}
class TextEditorMemento {
- text: string
+ getText(): string
}
class EditorHistory {
- history: array
+ save(memento: TextEditorMemento)
+ undo(): TextEditorMemento
}
TextEditor --> TextEditorMemento
EditorHistory --> TextEditorMemento
PHP’s object-oriented capabilities make it well-suited for implementing the Memento Pattern. The use of classes and encapsulation aligns with the pattern’s requirements. PHP’s dynamic typing allows for flexible handling of different types of state data.
The Memento Pattern is often confused with the Command Pattern, as both can be used to implement undo functionality. However, the Command Pattern encapsulates actions, while the Memento Pattern encapsulates state.
Experiment with the code examples by modifying the TextEditor class to include additional features, such as:
Remember, mastering design patterns is a journey. The Memento Pattern is just one of many tools in your toolkit. As you continue to explore and implement design patterns, you’ll gain a deeper understanding of how to create robust and maintainable software. Keep experimenting, stay curious, and enjoy the journey!