Enforce PHP Interface Implementation with Implements

In PHP, ensuring that classes adhere to a specific structure is crucial for building robust, decoupled, and maintainable applications. This article provides a straightforward guide on how to strictly enforce interface implementation in PHP using the implements keyword. You will learn how to define interfaces, apply them to classes, use type hinting for strict enforcement, and understand how PHP handles compliance errors at runtime.

Defining an Interface

An interface acts as a contract. It defines the method names, arguments, and return types that a class must implement, without providing the actual business logic.

To create an interface, use the interface keyword:

interface PaymentProcessorInterface
{
    public function processPayment(float $amount): bool;
}

Implementing the Interface

To enforce this contract on a class, use the implements keyword. Once a class implements an interface, it must define all the methods declared in that interface. The method signatures—including the number of arguments, type hints, and return types—must match the interface exactly.

class StripeProcessor implements PaymentProcessorInterface
{
    public function processPayment(float $amount): bool
    {
        // Payment processing logic goes here
        return true;
    }
}

How PHP Enforces the Contract

PHP strictly enforces interface implementation at the engine level. If a class claims to implement an interface but fails to define one of its methods, or defines a method with an incompatible signature, PHP will immediately halt execution and throw a fatal error.

For example, the following code will fail:

// This will trigger a Fatal Error
class PayPalProcessor implements PaymentProcessorInterface
{
    // Fatal Error: Class PayPalProcessor contains 1 abstract method 
    // and must therefore be declared abstract or implement the remaining methods
}

Similarly, changing the parameter type or return type in the class will trigger a fatal error due to signature incompatibility:

// This will also trigger a Fatal Error
class BankProcessor implements PaymentProcessorInterface
{
    // Error: Declaration of BankProcessor::processPayment(int $amount) 
    // must be compatible with PaymentProcessorInterface::processPayment(float $amount)
    public function processPayment(int $amount): bool
    {
        return true;
    }
}

Enforcing Interfaces via Type Hinting

Defining the interface is only the first step. To strictly enforce its usage throughout your application, you should use the interface name as a type hint in your functions and methods. This ensures that the receiving code only accepts objects that are guaranteed to have the required methods.

class OrderManager
{
    private PaymentProcessorInterface $paymentProcessor;

    // Type hinting enforces that only valid implementations can be injected
    public function __construct(PaymentProcessorInterface $paymentProcessor)
    {
        $this->paymentProcessor = $paymentProcessor;
    }

    public function checkout(float $total)
    {
        $this->paymentProcessor->processPayment($total);
    }
}

If you attempt to pass a class to OrderManager that does not implement PaymentProcessorInterface, PHP will throw a TypeError, preventing invalid objects from breaking your application logic.