Interfaces
An interface describes what a class can do without saying anything about how it does it. Where an abstract class (covered on its own page) can share real implementation and state across a family of related classes, an interface is pure contract: a list of method signatures that any implementing class promises to provide. Two classes with nothing else in common — say, a full customer Order and a single CreditCardPayment — can both promise "I can be charged" without being related to each other at all.
interface and implements
A Chargeable contract
<?php
interface Chargeable {
public function charge(float $amount): bool;
}
class CreditCardPayment implements Chargeable {
public function __construct(private string $cardNumber)
{
}
public function charge(float $amount): bool
{
echo "Charging \${$amount} to card ending in " . substr($this->cardNumber, -4) . "\n";
return true;
}
}
$payment = new CreditCardPayment('4111111111111234');
$payment->charge(59.99);Charging $59.99 to card ending in 1234
interface Chargeable declares charge() with no body at all — interfaces never contain implementation, only signatures. CreditCardPayment implements Chargeable is a promise: if the class doesn't actually define a matching charge() method, PHP refuses to compile it, the same way it refuses an abstract class missing its abstract methods.
Implementing multiple interfaces at once
This is the capability an abstract class doesn't give you: while a PHP class can extends only one parent, it can implements as many interfaces as it needs, separated by commas. An Order naturally satisfies more than one contract — it can be charged, and separately, it can be refunded.
Order implements two interfaces
<?php
interface Chargeable {
public function charge(float $amount): bool;
}
interface Refundable {
public function refund(float $amount): bool;
}
class Order implements Chargeable, Refundable {
private float $chargedAmount = 0;
public function charge(float $amount): bool
{
$this->chargedAmount = $amount;
echo "Order charged: \${$amount}\n";
return true;
}
public function refund(float $amount): bool
{
if ($amount > $this->chargedAmount) {
return false;
}
echo "Order refunded: \${$amount}\n";
return true;
}
}
$order = new Order();
$order->charge(120.00);
$order->refund(30.00);Order charged: $120.00 Order refunded: $30.00
Order owes both charge() and refund() because it lists both interfaces after implements. Any class — Order, CreditCardPayment, a future BankTransferPayment — can pick up exactly the set of contracts it needs, without being forced into a shared inheritance chain just to share a method signature.
Constants inside an interface
An interface can also declare constants, which every implementing class inherits automatically — useful for fixed values that are conceptually part of the contract itself, such as a status code every Refundable should recognize.
A constant defined on the interface
<?php
interface Refundable {
const MAX_REFUND_WINDOW_DAYS = 30;
public function refund(float $amount): bool;
}
class Order implements Refundable {
public function refund(float $amount): bool
{
echo 'Refund window: ' . self::MAX_REFUND_WINDOW_DAYS . " days\n";
return true;
}
}
echo Order::MAX_REFUND_WINDOW_DAYS, "\n";30
Just like a class constant, an interface constant cannot be reassigned, and it's reachable both through the interface name and through any implementing class's name.
Checking a contract with instanceof
Because an interface is a real type, you can test at runtime whether a given object satisfies it with instanceof — handy when a function receives a general object and needs to decide whether a particular capability is available before calling it.
Checking capability before acting on it
<?php
interface Refundable {
public function refund(float $amount): bool;
}
class Order implements Refundable {
public function refund(float $amount): bool
{
return true;
}
}
class GiftCard {
// Deliberately does NOT implement Refundable
}
function tryRefund(object $item, float $amount): void
{
if ($item instanceof Refundable) {
$item->refund($amount);
echo 'Refund processed' . "\n";
} else {
echo get_class($item) . ' cannot be refunded' . "\n";
}
}
tryRefund(new Order(), 15.00);
tryRefund(new GiftCard(), 15.00);Refund processed GiftCard cannot be refunded
tryRefund() never needed to know about Order or GiftCard specifically — it only cares whether the object in hand honors the Refundable contract. This is the practical payoff of programming against interfaces: code that accepts "anything Refundable" keeps working unchanged when a brand-new class starts implementing that interface next year.
interface Name { ... }declares method signatures (and optionally constants) with no implementation.class Foo implements InterfaceNamepromises Foo provides every method the interface declares.A class can implement multiple interfaces at once, even though it can extend only one parent class.
$object instanceof InterfaceNametests at runtime whether an object satisfies that contract.PHP refuses to load a class that claims
implementsan interface but leaves a method unimplemented.