PHP
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions
-
Section 4: Object-Oriented PHP
-
Section 5: Working with Data
-
Section 6: Modern PHP (PHP 8)
-
Section 7: Working with Files and Networking
-
Section 8: Common PHP Frameworks Overview
-
Section 9: Tooling and Ecosystem
-
Section 10: Practical Projects
-
Section 11: Interview Practice
-
Section 12: More Standard Library
-
Section 13: Data Structures and Algorithms in PHP
-
Section 14: More Practice Exercises
-
Section 15: More Security and Best Practices
-
Section 16: More Testing and Tooling
-
Section 17: WordPress-Style CMS Concepts
-
Section 18: Advanced OOP Practice
-
Section 19: More Web Fundamentals
-
Section 20: Database Practice
-
Section 21: PHP Manual: Array Functions
-
Section 22: PHP Manual: Date and Calendar Functions
-
Section 23: PHP Manual: Filesystem and Directory Functions
-
Section 24: PHP Manual: Filter and Var Handling
-
Section 25: PHP Manual: Math Functions
-
Section 26: PHP Manual: JSON and XML
-
Section 27: PHP Manual: Network and Stream Functions
-
Section 28: PHP Manual: Error and Exception Handling
-
Section 29: PHP Manual: Output Control and Misc
-
Section 30: PHP Manual: FTP, Zip, and Mail
-
Section 31: Modern PHP Frameworks Deep Dive
-
Section 32: PHP Design Patterns
-
Section 33: More Practice Exercises
-
Section 34: PHP Performance and Deployment
-
Section 35: More Interview Practice
-
Section 36: More PHP Standard Library
-
Section 37: PHP Concurrency and Async
-
Section 38: More Web Development Practice
-
Section 39: PHP Testing Deep Dive
-
Section 40: Composer and Package Development
-
Section 41: PHP Security Deep Dive
-
Section 42: More Practical Projects
-
Section 43: Legacy PHP Maintenance
-
Section 44: More Algorithm Practice
-
Section 45: Final Practice and Review
-
Section 46: PHP for E-Commerce Patterns
-
Section 47: PHP API Design Deep Dive
-
Section 48: PHP Caching Strategies
-
Section 49: PHP Queue and Background Jobs
-
Section 50: PHP Multi-Tenancy Patterns
-
Section 51: PHP Real-Time Features
-
Section 52: PHP CMS and Content Modeling
-
Section 53: PHP Internationalization
-
Section 54: More Framework-Specific Practice
-
Section 55: PHP Legacy Code Refactoring
-
Section 56: More Practice Projects Round 2
-
Section 57: PHP Command-Line Applications
-
Section 58: PHP and Microservices
-
Section 59: More Interview and Review Round 2
125: SPL Data Structures: SplStack, SplQueue, ArrayObject
For most of your career in PHP, you'll probably lean on the standard array for everything. It's the Swiss Army knife of the language. But there comes a point where using a generic array for a specific data structure isn't just "not ideal"—it's actually a performance bottleneck or a source of architectural confusion. That's where the Standard PHP Library (SPL) data structures come in. Specifically, SplStack, SplQueue, and ArrayObject.
The Performance Trap of array_shift
Let's say you're building a simple background job processor. You have a list of emails to send, and you want to process them in the order they arrived (First-In, First-Out). The naive approach is to use a standard array with array_push() to add items and array_shift() to pull them off the front.
$queue = [];
$queue[] = 'job_1';
$queue[] = 'job_2';
$queue[] = 'job_3';
while (!empty($queue)) {
$job = array_shift($queue);
// Process job...
}
This works perfectly fine when you have ten jobs. But here is the catch: array_shift() is expensive. Every time you pull an element off the front of a standard array, PHP has to re-index every single remaining element. If you have 10,000 items in that queue, you're performing thousands of unnecessary operations just to move the pointer. It's a silent killer of performance.
I usually tell my juniors to switch to SplQueue the moment the "list" serves a specific purpose. SplQueue is implemented as a doubly linked list, meaning removing an element from the front is an O(1) operation. It doesn't matter if you have ten items or ten million; the cost is the same.
$queue = new SplQueue();
$queue->enqueue('job_1');
$queue->enqueue('job_2');
$queue->enqueue('job_3');
while (!$queue->isEmpty()) {
$job = $queue->dequeue();
// Process job...
}
The same logic applies to SplStack (Last-In, First-Out). While array_pop() is actually quite efficient, using SplStack makes your intent clear to anyone reading your code. When I see $stack->push() and $stack->pop(), I know exactly how the data is flowing without having to trace the array manipulations.
When Arrays Aren't Enough: The Object Wrapper
Now, ArrayObject is a different beast entirely. You'll run into a problem where you want an array, but you need it to behave like an object. This usually happens when you're passing a collection into a method that expects an object, or when you want to implement a specific interface (like Countable or IteratorAggregate) on your data set.
If you pass a standard array to a function, PHP passes it by value (mostly). Even with references, it can get messy. If you wrap that data in an ArrayObject, you're dealing with a real object. You can pass it around, and every part of your application is mutating the same instance.
$config = new ArrayObject([
'db_host' => 'localhost',
'db_user' => 'root'
]);
function updateConfig(ArrayObject $config) {
$config['db_host'] = '127.0.0.1';
}
updateConfig($config);
echo $config['db_host']; // Outputs: 127.0.0.1
I find ArrayObject particularly useful when I'm building a Data Transfer Object (DTO) that needs to be flexible. You get the syntax of an array (the square brackets) but the power of an object. You can even override the offsetGet or offsetSet methods to add validation logic—something that's simply impossible with a primitive array.
📋 Practical Task
Implementation: Undo-Redo History Manager
You are building a text editor's history system. You need to implement a HistoryManager class that tracks changes to a document. Requirements:
- Use an
SplStackto store "Undo" actions. - Use an
SplStackto store "Redo" actions. - Implement a
saveAction($action)method: This should push the action onto the Undo stack and clear the Redo stack (since a new action invalidates the redo history). - Implement an
undo()method: This should pop the last action from the Undo stack and push it onto the Redo stack. - Implement a
redo()method: This should pop the last action from the Redo stack and push it back onto the Undo stack.
Create the class and demonstrate it by saving three different strings ("Typed 'Hello'", "Typed ' World'", "Deleted 'World'"), performing two undos, and then one redo. Print the current state of the Undo stack after each operation.
There are no comments for now.