The abstraction consists of exposing the essential part of a component and hiding the details that the user does not need.
So far we have worked with concrete classes: a Guerrero, a Dron, a Usuario. These are things you can instantiate (new Usuario()).
But sometimes we need to define concepts, not concrete things.
- You can’t buy “a vehicle” at the dealership. You buy a Ford (Car) or a Yamaha (Motorcycle). “Vehicle” is an abstraction.
- You can’t plug in “a USB”. You plug in a keyboard or a camera via USB. USB is a protocol (interface).
To handle these concepts in PHP, we have two tools: Abstract Classes and Interfaces.
Abstract classes: “is a…”
An abstract class is a half-finished class.
- It cannot be instantiated (
new AbstractClass❌ Error). - It can have normal methods (with code) and properties.
- It can have abstract methods: signatures without a body that force child classes to implement them.
It serves to create a common base for a family of objects.
abstract class PaymentMethod {
// Shared logic: All payment methods have a currency
public function __construct(protected string $currency = 'EUR') {}
// Concrete logic: Everyone converts currency the same way
public function getCurrency(): string {
return $this->currency;
}
// THE CONTRACT: I force child classes to define HOW they process
// I don't know how to do it, but I know they must.
abstract public function process(float $amount): void;
}Now we create the implementations:
class PayPal extends PaymentMethod {
public function process(float $amount): void {
echo "Paying $amount {$this->currency} with PayPal API...";
}
}
class Stripe extends PaymentMethod {
public function process(float $amount): void {
echo "Paying $amount {$this->currency} with Credit Card...";
}
}Key point: We use abstract when we want to share code (common properties and methods) and enforce a structure in a strictly related family (Vertical hierarchy).
Interfaces: “can do…”
An Interface is a pure contract.
- It does not implement method bodies; it defines their public signatures.
- It can declare constants and, since PHP 8.4, requirements for public properties via property hooks.
- A class can implement multiple interfaces.
It serves to define capabilities regardless of what the object is.
Imagine we want to save things to a JSON file. A User can be saved. An Order can be saved. But a User IS NOT an Order. They have nothing in common except that capability.
interface ExportableJson {
public function export(): string;
}
class User implements ExportableJson {
public function export(): string {
return json_encode(['name' => 'Luis']);
}
}
class Order implements ExportableJson {
public function export(): string {
return json_encode(['id' => 999, 'total' => 50]);
}
}Now we can have a function that accepts anything that fulfills the contract, regardless of what it is:
function saveToDisk(ExportableJson $object) {
file_put_contents('data.json', $object->export());
}This is pure Polymorphism. The saveToDisk function doesn’t care if you pass it a User or an Order. It only cares that it has the export method.
When do I use which?
This table summarizes the main differences.
| Feature | Abstract Class | Interface |
|---|---|---|
| Relationship | “Is a…” (Identity) | “Can do…” (Capability) |
| Code | Can have logic and state (variables). | Contracts for methods and public properties, without implementing their logic. |
| Inheritance | Single (extends). Only one parent. | Multiple (implements). Many interfaces. |
| Purpose | Don’t repeat common code (DRY). | Decouple. Define protocols. |
Interfaces in modern PHP
In modern PHP, interfaces are the foundation of solid design.
- Type declarations: We use interfaces in function parameters (
function process(LoggerInterface $logger)). - Dependency Injection: We never ask for a concrete class (e.g.,
MySQLConnection), we ask for an interface (DatabaseConnection). This way, if tomorrow we switch from MySQL to PostgreSQL, the code still works.
PHP 8.4 also allows an interface to require a readable, writable, or both property. This is an advanced feature; for most service contracts, you’ll still use methods.