PHP 8.1 Intersection Types Explained

This article explains the concept of intersection types introduced in PHP 8.1, demonstrating how they allow developers to enforce multiple interface constraints on a single value, and provides clear, practical examples of how to declare and use them in your code.

What is an Intersection Type?

An intersection type requires a value to satisfy multiple type constraints simultaneously. While a union type (declared with |) allows a value to be of type A or type B, an intersection type (declared with &) mandates that the value must be both type A and type B.

In PHP 8.1, intersection types are “pure,” meaning they can only be used with class and interface names. You cannot use them with scalar types like int, string, bool, or mixed.

How to Declare Intersection Types

To declare an intersection type, combine two or more interfaces or classes using the ampersand (&) symbol in your parameter types, return types, or property types.

Here is a practical example using interfaces:

interface Serializable {
    public function serialize(): string;
}

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

// A class must implement both interfaces to satisfy the intersection type
class ActivityReport implements Serializable, Loggable {
    public function serialize(): string {
        return "Report Data";
    }

    public function log(string $message): void {
        echo "Log: $message";
    }
}

// The parameter must be an object that implements both Serializable AND Loggable
function processData(Serializable&Loggable $item) {
    $data = $item->serialize();
    $item->log("Serialized data: " . $data);
}

$report = new ActivityReport();
processData($report); // Works perfectly

Important Rules and Limitations in PHP 8.1

When working with intersection types in PHP 8.1, keep the following rules in mind: