Welcome! Today, we will delve into managing a document's editing history using stacks in PHP. Imagine building a text editor; you would need to handle actions like adding text, undoing changes, and redoing them. We will see how these features can be efficiently implemented using stacks, which are represented by arrays in PHP. PHP's built-in functions like array_push and array_pop allow us to effortlessly manage these stacks. By the end of this lesson, you will possess an in-depth understanding of applying stacks in practical scenarios using PHP.
Introducing Methods to Implement
Before starting the coding portion, let's dissect the methods we will implement. These methods will manage a document's edit history, allowing us to apply changes, undo them, and redo them effectively.
function applyChange($change): This method applies a change to the document. The change, represented as a string, is stored in a way that allows us to remember the order of applied changes. Any previously undone changes are discarded.
function undo(): This method undoes the most recent change and allows us to store it for a possible redo. It returns the change that was undone, or null if there are no changes available to undo.
function redo(): This method redoes the most recent undone change, making it active again. It returns the change that was redone, or null if there are no changes available to redo.
function getChanges(): This method returns an array of all applied changes in the order they were applied.
Methods Implementation with Stacks
To implement these methods efficiently, we'll use arrays in PHP to simulate stack behavior. Arrays provide dynamic resizing and efficient element insertion or removal from the end. Stacks are ideal for keeping track of applied changes and undone changes because of their LIFO (Last In, First Out) property. The most recent change is always at the top, making it easy to undo and redo.
Let's break down each method's implementation and study how they interact with the stacks.
Step 1: Define the Class and Initialize the Stacks
Let's implement the solution step-by-step. First, we define our class and set up the initial state.
Here, DocumentHistory is the class, and we initialize two empty arrays named $changesStack to act as our stack of applied changes, and $redoStack to represent our stack for undone changes.
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal
Step 2: Implement the 'applyChange' Method
Step 3: Implement the 'undo' Method
Step 4: Implement the 'redo' Method
Step 5: Implement the 'getChanges' Method
The Final Implementation
Summary
In today's lesson, we learned how to manage a document's editing history using stacks in PHP. We implemented methods to apply changes, undo the last change, redo the most recent undone change, and retrieve all applied changes. This exercise provided us with practical experience in using PHP arrays to efficiently track and revert operations in a real-life scenario. Keep practicing similar challenges to deepen your understanding of PHP's data-handling capabilities. Fantastic job today, and keep up the good work!
Next, we put into effect the method to apply changes.
PHP
class DocumentHistory { private $changesStack = []; private $redoStack = []; public function applyChange($change) { array_push($this->changesStack, $change); $this->redoStack = []; // Clear the redo stack }}
With applyChange, we take a string $change and append it to the $changesStack array using array_push. Additionally, we reinitialize the $redoStack to ensure that once a new change is applied, any previously undone changes cannot be redone.
Now, we will implement the method to undo the most recent change.
PHP
class DocumentHistory { private $changesStack = []; private $redoStack = []; public function applyChange($change) { array_push($this->changesStack, $change); $this->redoStack = []; } public function undo() { if (empty($this->changesStack)) { return null; } $change = array_pop($this->changesStack); array_push($this->redoStack, $change); return $change; }}
Here, undo checks if the $changesStack is empty. If it is, it returns null. Otherwise, it pops the last item from the array using array_pop, pushes it to the $redoStack, and returns the undone change.
Now we'll create the method to redo the most recent undone change.
PHP
class DocumentHistory { private $changesStack = []; private $redoStack = []; public function applyChange($change) { array_push($this->changesStack, $change); $this->redoStack = []; } public function undo() { if (empty($this->changesStack)) { return null; } $change = array_pop($this->changesStack); array_push($this->redoStack, $change); return $change; } public function redo() { if (empty($this->redoStack)) { return null; } $change = array_pop($this->redoStack); array_push($this->changesStack, $change); return $change; }}
The redo method checks if the $redoStack is empty. If it is, it returns null. Otherwise, it pops the last item from the array, pushes it back to the $changesStack, and returns the redone change.
Lastly, we implement the method to retrieve all applied changes.
PHP
class DocumentHistory { private $changesStack = []; private $redoStack = []; public function applyChange($change) { array_push($this->changesStack, $change); $this->redoStack = []; } public function undo() { if (empty($this->changesStack)) { return null; } $change = array_pop($this->changesStack); array_push($this->redoStack, $change); return $change; } public function redo() { if (empty($this->redoStack)) { return null; } $change = array_pop($this->redoStack); array_push($this->changesStack, $change); return $change; } public function getChanges() { return $this->changesStack; }}
The getChanges method simply returns a copy of the $changesStack array, which includes all changes applied to the document in the order they were applied.
Let's test this final implementation of DocumentHistory with an example:
PHP
class DocumentHistory { private $changesStack = []; private $redoStack = []; public function applyChange($change) { array_push($this->changesStack, $change); $this->redoStack = []; } public function undo() { if (empty($this->changesStack)) { return null; } $change = array_pop($this->changesStack); array_push($this->redoStack, $change); return $change; } public function redo() { if (empty($this->redoStack)) { return null; } $change = array_pop($this->redoStack); array_push($this->changesStack, $change); return $change; } public function getChanges() { return $this->changesStack; }}$docHist = new DocumentHistory();// Apply changes$docHist->applyChange("Added header");$docHist->applyChange("Added footer");print_r($docHist->getChanges()); // Output: Array ( [0] => Added header [1] => Added footer )// Undo last changeecho $docHist->undo() . PHP_EOL; // Output: Added footerprint_r($docHist->getChanges()); // Output: Array ( [0] => Added header )// Redo last undone changeecho $docHist->redo() . PHP_EOL; // Output: Added footerprint_r($docHist->getChanges()); // Output: Array ( [0] => Added header [1] => Added footer )// Undo all changesecho $docHist->undo() . PHP_EOL; // Output: Added footerecho $docHist->undo() . PHP_EOL; // Output: Added headerprint_r($docHist->getChanges()); // Output: Array ( )// Try undoing when no changes are leftecho $docHist->undo() . PHP_EOL; // Output: // Redo changesecho $docHist->redo() . PHP_EOL; // Output: Added headerecho $docHist->redo() . PHP_EOL; // Output: Added footerprint_r($docHist->getChanges()); // Output: Array ( [0] => Added header [1] => Added footer )// Try redoing when no changes are left to redoecho $docHist->redo() . PHP_EOL; // Output: