DEV Community

arasosman
arasosman

Posted on • Originally published at mycuriosity.blog

How to Handle PHP's Intersection Types

Quick Fix

You can solve complex type requirements by using intersection types with the & operator:

<?php

interface Loggable {
    public function log(string $message): void;
}

interface Cacheable {
    public function cache(): array;
    public function invalidateCache(): void;
}

interface Serializable {
    public function serialize(): string;
    public function unserialize(string $data): void;
}

// Function requiring multiple interfaces
function processEntity(Loggable&Cacheable $entity): void {
    $entity->log("Processing started");
    $data = $entity->cache();
    // Process the entity...
    $entity->invalidateCache();
}

// Class implementing multiple interfaces
class UserService implements Loggable, Cacheable, Serializable {
    private array $userData = [];

    public function log(string $message): void {
        error_log("[UserService] " . $message);
    }

    public function cache(): array {
        return $this->userData;
    }

    public function invalidateCache(): void {
        $this->userData = [];
    }

    public function serialize(): string {
        return json_encode($this->userData);
    }

    public function unserialize(string $data): void {
        $this->userData = json_decode($data, true);
    }
}

// Usage
$userService = new UserService();
processEntity($userService); // ✅ Works - implements both interfaces

// More complex intersection with class and interface
function handleAdvanced(UserService&Loggable&Cacheable $service): void {
    // Must be UserService AND implement both interfaces
    $service->log("Advanced handling");
    $service->cache();
}
Enter fullscreen mode Exit fullscreen mode

Behind the Scenes

Intersection types ensure objects satisfy all specified contracts:

  1. Multiple Requirements: Object must implement every interface/class in the intersection
  2. Type Safety: Compile-time checking prevents incompatible objects
  3. Flexible Design: Create precise type contracts without creating new interfaces

Key Benefits:

  • Enforce multiple behaviors without inheritance
  • Create more specific type requirements
  • Improve code documentation and IDE support
  • Enable better static analysis

Unlike union types (|) that accept "this OR that", intersection types require "this AND that".

Top comments (0)