PHP Abstract Classes and Interfaces
Abstract classes and interfaces are two tools for defining contracts in object-oriented PHP — enforcing that certain methods must exist in any class that builds on them. They help structure large codebases by establishing clear expectations for how objects should behave, without dictating how that behavior is implemented.
Abstract Classes
An abstract class is a class that cannot be instantiated directly. It exists purely as a base for other classes to extend. It can contain both abstract methods (declared but not implemented) and regular methods (fully implemented). Any class that extends an abstract class must provide implementations for all abstract methods.
<?php
abstract class Shape {
protected string $color;
public function __construct(string $color) {
$this->color = $color;
}
// Abstract method - must be implemented by child classes
abstract public function area(): float;
abstract public function perimeter(): float;
// Regular method - shared by all child classes
public function describe(): string {
return "A " . $this->color . " shape with area " . round($this->area(), 2)
. " and perimeter " . round($this->perimeter(), 2) . ".";
}
}
class Circle extends Shape {
public function __construct(private float $radius, string $color) {
parent::__construct($color);
}
public function area(): float {
return M_PI * $this->radius ** 2;
}
public function perimeter(): float {
return 2 * M_PI * $this->radius;
}
}
class Rectangle extends Shape {
public function __construct(
private float $width,
private float $height,
string $color
) {
parent::__construct($color);
}
public function area(): float {
return $this->width * $this->height;
}
public function perimeter(): float {
return 2 * ($this->width + $this->height);
}
}
$circle = new Circle(5, "red");
$rect = new Rectangle(4, 6, "blue");
echo $circle->describe();
// A red shape with area 78.54 and perimeter 31.42.
echo $rect->describe();
// A blue shape with area 24 and perimeter 20.
// new Shape("green"); // Fatal error - cannot instantiate abstract class
?>
Interfaces
An interface is a pure contract. It declares a set of method signatures that any implementing class must fulfill. Interfaces contain no property values and no method implementations — only method signatures. A class implements an interface using the implements keyword.
<?php
interface Printable {
public function printDocument(): void;
public function getPageCount(): int;
}
interface Scannable {
public function scan(): string;
}
class Invoice implements Printable {
private array $items;
public function __construct(array $items) {
$this->items = $items;
}
public function printDocument(): void {
foreach ($this->items as $item) {
echo $item . "\n";
}
}
public function getPageCount(): int {
return (int)ceil(count($this->items) / 10);
}
}
$invoice = new Invoice(["Item 1 - $50", "Item 2 - $30", "Item 3 - $75"]);
$invoice->printDocument();
echo "Pages: " . $invoice->getPageCount();
?>
Implementing Multiple Interfaces
PHP does not allow a class to extend more than one class, but a class can implement multiple interfaces. This is one way to achieve multiple inheritance-like behavior in PHP.
<?php
interface Loggable {
public function log(string $message): void;
}
interface Cacheable {
public function cache(string $key, $value): void;
public function retrieve(string $key);
}
class DataService implements Loggable, Cacheable {
private array $cache = [];
public function log(string $message): void {
echo "[LOG] " . date("H:i:s") . " - " . $message . "\n";
}
public function cache(string $key, $value): void {
$this->cache[$key] = $value;
$this->log("Cached: $key");
}
public function retrieve(string $key) {
return $this->cache[$key] ?? null;
}
}
$service = new DataService();
$service->cache("user_42", ["name" => "Alice"]);
$user = $service->retrieve("user_42");
echo $user['name']; // Alice
?>
Interface Inheritance
Interfaces can extend other interfaces, building a hierarchy of contracts.
<?php
interface Readable {
public function read(): string;
}
interface Writable {
public function write(string $content): void;
}
interface ReadWritable extends Readable, Writable {
public function seek(int $position): void;
}
class FileStream implements ReadWritable {
private string $content = "";
private int $position = 0;
public function read(): string {
return substr($this->content, $this->position);
}
public function write(string $content): void {
$this->content .= $content;
}
public function seek(int $position): void {
$this->position = $position;
}
}
?>
Abstract Class vs Interface — When to Use Each
| Feature | Abstract Class | Interface |
|---|---|---|
| Can have implemented methods | Yes | No (constants only) |
| Can have properties | Yes | No |
| Can be extended by one class | Yes (one parent only) | N/A |
| Can be implemented by many classes | N/A | Yes (unlimited) |
| A class can implement multiple | No (only one parent) | Yes |
| Access modifiers on methods | Yes | Public only |
| Use when | Sharing code between related classes | Defining a contract across unrelated classes |
Key Points
- Abstract classes cannot be instantiated — they serve as base templates for child classes.
- Abstract methods declared in a parent must be implemented by every non-abstract child class.
- Interfaces define a pure contract — method signatures only, no implementation.
- A class implements an interface with the
implementskeyword and must fulfill all declared methods. - A class can implement multiple interfaces but can only extend one abstract class.
- Use an abstract class when child classes share common code; use an interface when unrelated classes share a common contract.
