PHPInterfaces

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
<?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
<?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
<?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
<?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.

A missing method is caught at compile time, not silently ignored
If a class declares `implements Chargeable` but never actually writes a `charge()` method, PHP raises a fatal error the moment the class is loaded — "Class must implement interface method." Unlike a typo'd array key or an undefined property, an unfulfilled interface contract cannot slip through to production unnoticed.
  • interface Name { ... } declares method signatures (and optionally constants) with no implementation.

  • class Foo implements InterfaceName promises 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 InterfaceName tests at runtime whether an object satisfies that contract.

  • PHP refuses to load a class that claims implements an interface but leaves a method unimplemented.

Interfaces vs. abstract classes, in one line
An abstract class answers "what do these related classes share?" — an interface answers "what can this object do, regardless of what it otherwise is?"
Tip
Design interfaces around a single capability — `Chargeable`, `Refundable` — rather than one big interface bundling every method a payment-related class might ever need. Small, focused interfaces let classes like `Order` mix and match exactly the contracts they actually fulfill, and let functions like `tryRefund()` depend on the one capability they actually use.