Intersection Types in PHP 8.1

Intersection Types in PHP 8.1

Since PHP 8.0, we can use union types which allows to provide two or more types for parameters, return values, and properties. Given value should be one of the specified types.

Since PHP 8.1, intersection types can be used. It requires value to be all of the specified class and interface types. We can specify any number of types which are combined by ampersand (&) using the syntax:

class_1&class_2&interface_1&interface_2&...&class_n&interface_n

Intersection types are allowed anywhere types are accepted: parameters, return values, and properties.

Storage.php

<?php

class Storage
{
    private ArrayAccess&Countable $container;

    public function getContainer(): Countable&ArrayAccess
    {
        return $this->container;
    }

    public function setContainer(Countable&ArrayAccess $container): void
    {
        $this->container = $container;
    }
}

For example, with intersection types now possible to check if class implements both ArrayAccess and Countable interfaces. Parameter $container should be an instance of the class that implements both specified interfaces (e.g. CountableArrayObject class). Passing any instance of the class that does not implement both interfaces gives a fatal error.

CountableArrayObject.php

<?php

class CountableArrayObject implements ArrayAccess, Countable
{
    public function offsetExists(mixed $offset): bool { return false; }
    public function offsetGet(mixed $offset): mixed { return null; }
    public function offsetSet(mixed $offset, mixed $value): void {}
    public function offsetUnset(mixed $offset): void {}
    public function count(): int { return 0; }
}

Nullable types

PHP allows to use nullable types (e.g. ?string or string|null). We cannot to use intersection types with nullable type notation. For example, ?Countable&ArrayAccess or Countable&ArrayAccess&null are incorrect.

Combination with union types

Intersection types together with union types cannot be used. For example, ArrayAccess&Countable|Iterator is illegal and cannot be used to define type.

Class and interface types

Only classes and interfaces can be used as part of the intersection types. Scalar types (bool, int, float, string), compound types (array, object, callable, iterable), void, mixed, never, and other types are not allowed. For example, int&float is illegal.

Duplicate types

Class or inteface cannot be used more than one time as part of the intersection types. This means that we cannot define type declarations such as ArrayAccess&Countable&ArrayAccess. It will produce a fatal error.

Leave a Comment

Cancel reply

Your email address will not be published.