An interface is a contract. It lists the methods a class must provide, but contains no code. Any class that implements the interface promises to have those methods.
<?php
interface Logger
{
public function log(string $message): void;
}
class FileLogger implements Logger
{
public function log(string $message): void
{
echo "[file] $message\n";
}
}
class ScreenLogger implements Logger
{
public function log(string $message): void
{
echo "[screen] $message\n";
}
}
function run(Logger $logger): void
{
$logger->log("Started");
}
run(new FileLogger());
run(new ScreenLogger());
[file] Started
[screen] Started
The function run() does not care which logger it gets. It only needs something that can log(). That makes the code flexible: you can swap loggers without changing run().
The rules
- All interface methods are public and have no body.
- A class uses
implementsand must write every method. - A class can implement many interfaces (separated by commas).
- An interface can extend other interfaces.
<?php
interface Printable
{
public function print(): string;
}
interface Savable
{
public function save(): bool;
}
class Document implements Printable, Savable
{
public function print(): string
{
return "Printing document";
}
public function save(): bool
{
return true;
}
}
$d = new Document();
echo $d->print() . "\n";
var_dump($d instanceof Savable);
Printing document
bool(true)
Interface constants
<?php
interface HasVersion
{
const VERSION = "2.0";
}
class Plugin implements HasVersion {}
echo Plugin::VERSION;
2.0
Extending an interface
<?php
interface Reader
{
public function read(): string;
}
interface ReaderWriter extends Reader
{
public function write(string $data): void;
}
echo "ReaderWriter requires read() and write()";
ReaderWriter requires read() and write()
Interfaces are types
You can use an interface as a parameter type, a return type or a property type. This is the basis of dependency injection (see Dependency Injection).
Built-in interfaces worth knowing
| Interface | Gives your class the ability to… |
|---|---|
Countable | work with count($object) |
IteratorAggregate / Iterator | be used in foreach |
ArrayAccess | be used like an array ($obj["key"]) |
Stringable | be used as a string |
JsonSerializable | control json_encode() |
<?php
class Playlist implements Countable
{
private array $songs = ["A", "B", "C"];
public function count(): int
{
return count($this->songs);
}
}
echo count(new Playlist());
3
When to use an interface
- When several classes do the same job in different ways (loggers, payment gateways, storage).
- When you want to write code that does not depend on a specific class.
- When you want to test code by swapping a real service for a fake one.
Name by role
Logger, PaymentGateway, Cache. Some projects add Interface as a suffix, others do not. Follow your project’s style.