Interfaces and abstract classes
Sometimes what matters is not how an object is built but what it can do. An interface describes exactly that: a list of methods a class must have.
Interfaces
An interface lists methods without bodies. A class that implements it must declare all of them:
<?php
interface Shape
{
public function area(): float;
}
class Rectangle implements Shape
{
public function __construct(private float $width, private float $height) {}
public function area(): float
{
return $this->width * $this->height;
}
}
class Circle implements Shape
{
public function __construct(private float $radius) {}
public function area(): float
{
return 3.14159 * $this->radius ** 2;
}
}
function printArea(Shape $shape): void
{
echo $shape->area(), "\n";
}
printArea(new Rectangle(2, 3)); // 6
printArea(new Circle(1)); // 3.14159The printArea() function accepts any object that implements Shape. It does not care whether it is a rectangle or a circle — having an area() method is enough.
Why it matters
An interface is a contract between parts of a program. When you add a new shape you do not change printArea(): implementing the interface is enough. That makes a program easier to extend and to test.
Built-in interfaces
PHP ships with interfaces that connect your classes to language features. For example, Countable lets you pass an object to the count() function:
<?php
class Cart implements Countable
{
private array $items = [];
public function add(string $item): void
{
$this->items[] = $item;
}
public function count(): int
{
return count($this->items);
}
}
$cart = new Cart();
$cart->add('tea');
$cart->add('coffee');
echo count($cart); // 2A class may implement several interfaces at once — list them separated by commas.
Abstract classes
An abstract class is a template: some of its methods are complete, while others are only declared and must be provided by child classes:
<?php
abstract class Report
{
abstract protected function body(): string;
public function render(): string
{
return "=== Report ===\n" . $this->body();
}
}
class SalesReport extends Report
{
protected function body(): string
{
return 'Sold: 42';
}
}
echo (new SalesReport())->render();The shared part — the header — is written once, and each report defines its own content.
Which one to choose
| Interface | Abstract class | |
|---|---|---|
| Ready-made code | No | Possible |
| Properties | No | Yes |
| How many you can use | Several | One |
If you only need to describe what an object can do, use an interface. If the children share code, use an abstract class.
A common mistake
You cannot create an object of an interface or an abstract class: new Shape() throws an error. Objects are created only from regular classes that implement them.