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
19: Abstract Classes
I see this a lot when developers start building larger systems. You want to create a "blueprint" for a set of related classes, so you use an abstract class. But then, you run into a fatal error that stops the whole site from loading. Let's look at a payment system example where this usually happens.
<?php
abstract class PaymentGateway {
protected $apiKey;
public function __construct($apiKey) {
$this->apiKey = $apiKey;
}
// Every gateway MUST have a way to process the payment
abstract public function processPayment($amount);
}
class StripeGateway extends PaymentGateway {
public function execute($amount) {
return "Processing \${$amount} via Stripe...";
}
}
$stripe = new StripeGateway('sk_test_123');
echo $stripe->processPayment(100);
?>
The "Missing Implementation" Crash
If you try to run the code above, PHP is going to throw a Fatal error. It'll tell you that StripeGateway contains one abstract method and must therefore be declared abstract or implement the remaining methods.
Here is the problem: in the PaymentGateway class, I defined abstract public function processPayment($amount). By doing this, I'm making a pinky-promise to PHP that every single class that extends PaymentGateway will have a method called processPayment. However, in StripeGateway, I named the method execute() instead. PHP doesn't care that the logic is there; it only cares that the specific name promised in the abstract class is missing.
Fixing the Contract
To fix this, we have to align the child class with the parent's requirements. We don't change the abstract class—that's our "contract"—we change the implementation.
<?php
abstract class PaymentGateway {
protected $apiKey;
public function __construct($apiKey) {
$this->apiKey = $apiKey;
}
abstract public function processPayment($amount);
}
class StripeGateway extends PaymentGateway {
// Fixed: The method name now matches the abstract definition exactly
public function processPayment($amount) {
return "Processing \${$amount} via Stripe using key {$this->apiKey}...";
}
}
$stripe = new StripeGateway('sk_test_123');
echo $stripe->processPayment(100); // Now it works!
?>
Why we can't just use a regular class
You might be wondering, "Why not just make PaymentGateway a normal class and leave the method empty?"
I've tried that in the past, and it's a recipe for bugs. If you use a regular class with an empty method, and you (or a teammate) create a new PayPalGateway but forget to write the payment logic, the code will run silently and do absolutely nothing. You won't know it's broken until a customer complains that their payment didn't go through.
By using an abstract class, you are forcing the error to happen during development. PHP refuses to even compile the code if the child class is missing a required method. It's a safety net that ensures your application remains consistent as it grows.
Preventing Direct Instantiation
Another huge benefit is that you can't do this: $gateway = new PaymentGateway('key');.
Since PaymentGateway is abstract, PHP prevents you from creating an object of that type. This makes sense—what would a "generic" payment gateway even do? It doesn't have a specific API to talk to. Abstract classes are meant to be inherited, not instantiated. I use them whenever I want to share some common logic (like the apiKey property and constructor) while still forcing child classes to handle the specific "how-to" of a process.
📋 Practical Task
Building a Multi-Format File Exporter
You are building a system that needs to export data in different formats (JSON and XML). To ensure every exporter follows the same rules, you need to use an abstract class.
Your Requirements:
- Create an abstract class called
FileExporter. - The
FileExportershould have a protected property$filenameand a constructor to set it. - The
FileExportermust define an abstract method calledexport(array $data). - Create a concrete class
JsonExporterthat extendsFileExporterand implements theexportmethod to return the data as a JSON string (usejson_encode) prefixed with "JSON Export to [filename]: ". - Create a concrete class
XmlExporterthat extendsFileExporterand implements theexportmethod to return a simple string simulating XML (e.g., "<xml>...</xml>") prefixed with "XML Export to [filename]: ".
Testing your code: Instantiate both exporters with different filenames and a sample array of data, then echo the results of their export() methods.
There are no comments for now.