Interfaces and Multiple Contracts
An interface is a promise of behaviour. A class can implement many at once, which is how PHP does 'is-a' without single-inheritance limits.
An interface says what a class can do, never how. Program against the interface and you can swap the concrete class freely — the essence of loose coupling. A class can only extend one parent, but it can implements any number of interfaces, separated by commas.
Easy example
<?php
interface Greetable {
public function greet(): string;
}
class Robot implements Greetable {
public function greet(): string {
return 'BEEP BOOP';
}
}
echo (new Robot())->greet();Interfaces can also declare public constants and can themselves extend multiple other interfaces, letting you compose bigger contracts from small ones.
Example
When to use it
- Define a Renderable interface so blade templates and JSON responses share the same render() contract.
- Implement multiple interfaces (Countable, Iterator) on a custom collection class to make it work with foreach and count().
- Use interface type hints in a dependency-injection container to resolve concrete implementations at runtime.
More examples
Multiple interface implementation
A class can implement any number of interfaces, satisfying multiple unrelated contracts without multiple inheritance.
<?php
interface Stringable {
public function __toString(): string;
}
interface JsonSerializable {
public function jsonSerialize(): mixed;
}
class Money implements Stringable, JsonSerializable {
public function __construct(
private int $cents,
private string $currency = 'USD'
) {}
public function __toString(): string {
return number_format($this->cents / 100, 2) . ' ' . $this->currency;
}
public function jsonSerialize(): mixed {
return ['cents' => $this->cents, 'currency' => $this->currency];
}
}
$m = new Money(1999);
echo $m; // 19.99 USD
echo json_encode($m->jsonSerialize()); // {"cents":1999,"currency":"USD"}Interface as type hint
Type-hinting against Cache lets render() work with any cache implementation — Redis, Memcached, or a test stub.
<?php
interface Cache {
public function get(string $key): mixed;
public function set(string $key, mixed $value, int $ttl = 60): void;
}
class ArrayCache implements Cache {
private array $store = [];
public function get(string $key): mixed { return $this->store[$key] ?? null; }
public function set(string $key, mixed $value, int $ttl = 60): void {
$this->store[$key] = $value;
}
}
function render(string $template, Cache $cache): string {
$cached = $cache->get($template);
if ($cached !== null) return $cached;
$result = "<html>$template</html>";
$cache->set($template, $result);
return $result;
}
echo render('home', new ArrayCache());Interface extending interface
Interfaces can extend other interfaces, building a hierarchy of contracts without requiring a class hierarchy.
<?php
interface Readable {
public function read(): string;
}
interface ReadWritable extends Readable {
public function write(string $data): void;
}
class FileStream implements ReadWritable {
private string $buffer = '';
public function read(): string { return $this->buffer; }
public function write(string $data): void { $this->buffer .= $data; }
}
$s = new FileStream();
$s->write('Hello');
echo $s->read(); // Hello
Discussion