Skip to content

PHP Interfaces — Complete Guide to Contracts and Polymorphism

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about PHP Interfaces. We cover key concepts, practical examples, and best practices to help you master this topic.

PHP interfaces define contracts that implementing classes must fulfill, enabling polymorphism, loose coupling, and interchangeable implementations.

What You'll Learn

By the end of this tutorial, you'll define interfaces, implement them in classes, use multiple interfaces, understand covariant returns, and design flexible systems with interface-based contracts.

Why Interfaces Matter

Interfaces decouple what a class does from how it does it. Code written against interfaces is flexible, testable with mocks, and supports Dependency Injection patterns.

Real-World Use

A notification system defines a NotifierInterface. EmailNotifier, SMSNotifier, and PushNotifier implement it. The application switches between implementations without changing notification logic.

Interfaces Learning Path

flowchart LR
  A[Inheritance] --> B[Interfaces]
  B --> C[Traits]
  C --> D[Namespaces]
  D --> E[Composer]
  A --> F{You Are Here}
  style F fill:#f90,color:#fff

Defining and Implementing Interfaces

<?php
interface LoggerInterface {
    public function log(string $message): void;
    public function getLogs(): array;
}
class FileLogger implements LoggerInterface {
    private array $logs = [];
    public function log(string $message): void {
        $this->logs[] = "[" . date("Y-m-d H:i:s") . "] " . $message;
        file_put_contents("app.log", end($this->logs) . "\n", FILE_APPEND);
    }
    public function getLogs(): array {
        return $this->logs;
    }
}
$logger = new FileLogger();
$logger->log("User logged in");

Multiple Interfaces

<?php
interface Cacheable {
    public function getCacheKey(): string;
    public function getCacheTTL(): int;
}
interface Exportable {
    public function toArray(): array;
}
class Product implements Cacheable, Exportable {
    public function __construct(
        private int $id,
        private string $name,
        private float $price
    ) {}
    public function getCacheKey(): string { return "product_{$this->id}"; }
    public function getCacheTTL(): int { return 3600; }
    public function toArray(): array {
        return ["id" => $this->id, "name" => $this->name, "price" => $this->price];
    }
}

Interface Inheritance

<?php
interface RepositoryInterface {
    public function find(int $id): ?array;
    public function findAll(): array;
}
interface CacheableRepositoryInterface extends RepositoryInterface {
    public function clearCache(): void;
}
class CachedUserRepository implements CacheableRepositoryInterface {
    public function find(int $id): ?array {
        return ["id" => $id, "name" => "Alice", "cached" => true];
    }
    public function findAll(): array { return []; }
    public function clearCache(): void { echo "Cache cleared\n"; }
}

Type Hinting with Interfaces

<?php
interface PaymentGateway {
    public function charge(float $amount, array $cardInfo): bool;
}
class StripeGateway implements PaymentGateway {
    public function charge(float $amount, array $cardInfo): bool {
        echo "Charging \${$amount} via Stripe\n";
        return true;
    }
}
class PayPalGateway implements PaymentGateway {
    public function charge(float $amount, array $cardInfo): bool {
        echo "Charging \${$amount} via PayPal\n";
        return true;
    }
}
function processPayment(PaymentGateway $gateway, float $amount): void {
    $gateway->charge($amount, ["number" => "4111..."]);
}
processPayment(new StripeGateway(), 99.99);
processPayment(new PayPalGateway(), 49.99);

Interface Constants

<?php
interface StatusCodes {
    const SUCCESS = 200;
    const NOT_FOUND = 404;
    const ERROR = 500;
}
class Response implements StatusCodes {
    public static function json(int $code, mixed $data): void {
        http_response_code($code);
        echo json_encode(["status" => $code, "data" => $data]);
    }
}
Response::json(StatusCodes::SUCCESS, ["message" => "OK"]);

Common Mistakes

1. Not Implementing All Interface Methods

A class implementing an interface must implement all its methods. Missing any method causes a fatal error.

2. Changing Method Signatures in Implementation

Implementing methods must have compatible signatures (same or contravariant parameters, covariant return types).

3. Overusing Interfaces

Not everything needs an interface. Add interfaces for extension points, not for every class.

4. Interface Pollution

An interface with too many methods violates Interface Segregation Principle. Split into smaller, focused interfaces.

5. Forgetting Type Hints in Implementation

Interface method signatures with typed parameters must be matched in the implementation.

Practice Questions

1. What is the difference between an interface and an abstract class?

Interfaces define only method signatures (no implementation). Abstract classes can provide default implementations and properties.

2. Can a class implement multiple interfaces?

Yes. A class can implement multiple interfaces: class MyClass implements InterfaceA, InterfaceB.

3. Can interfaces have properties?

No. Interfaces can only define method signatures and constants. Properties belong to classes.

4. What is polymorphism in the context of interfaces?

Different classes implementing the same interface can be used interchangeably through the interface type.

5. Challenge: Create a CacheInterface and implement FileCache and RedisCache adapters.

<?php
interface CacheInterface {
    public function get(string $key): mixed;
    public function set(string $key, mixed $value, int $ttl = 3600): void;
    public function delete(string $key): void;
}
class FileCache implements CacheInterface { /* implementation */ }
class RedisCache implements CacheInterface { /* implementation */ }
function getUser(CacheInterface $cache, int $id): array {
    $key = "user:$id";
    if ($data = $cache->get($key)) return $data;
    $user = ["id" => $id, "name" => "Alice"];
    $cache->set($key, $user);
    return $user;
}

FAQ

Can an interface extend another interface?

Yes. interface B extends A {}. The implementing class must satisfy all methods from both interfaces.

Can interfaces have constructors?

No. Interfaces cannot define constructors. The constructor is an implementation detail.

What is covariance and contravariance?

Covariance allows a method to return a more specific type. Contravariance allows parameters to accept a more general type.

Can I type hint against an interface?

Yes. function process(PaymentGateway $gateway) accepts any class implementing PaymentGateway.

How do interfaces support testing?

Interfaces let you mock dependencies. Tests can use mock implementations of interfaces without real infrastructure.

Mini Project: Cache System

Build a cache system with interchangeable backends via interfaces.

<?php
interface CacheInterface {
    public function get(string $key): mixed;
    public function set(string $key, mixed $value, int $ttl = 3600): void;
    public function delete(string $key): void;
    public function clear(): void;
}
class ArrayCache implements CacheInterface {
    private array $store = [];
    public function get(string $key): mixed { return $this->store[$key] ?? null; }
    public function set(string $key, mixed $value, int $ttl = 3600): void {
        $this->store[$key] = $value;
    }
    public function delete(string $key): void { unset($this->store[$key]); }
    public function clear(): void { $this->store = []; }
}
$cache = new ArrayCache();
$cache->set("name", "Alice");
echo $cache->get("name");  // Alice

What's Next

PHP Traits PHP Namespaces PHP Composer Autoload

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro