Skip to main content

PHP8 - Union Types

·416 words·2 mins·
Table of Contents

In the spirit of the upcoming PHP 8.0 release1 I’ve decided to write a few articles about features that I’m looking forward to. In this first part we’re going to cover Union Types2. Yes, at long last PHP is getting proper support for Unions!

So what are unions
#

The tldr version of this, Unions allow you to declare multiple types for arguments, return types and class properties.

Before PHP 8.0
#

Before PHP8, Union types already existed to some hacky degree.

Nullable types
#

By prefixing a ? a type could also be nullable

function printMe(?string $foo) {
    echo $foo;
}


printMe('tralala');
printMe(null);

iterable type
#

Iterables3 are array|Traversable

function foo(iterable $iterable) {
    foreach ($iterable as $value) {
        // ...
    }
}

PHPDoc
#

Union Types can be declared in PHPDoc4. Of course the downside to this is that PHP will run your code no matter what nonsense you pass

class Example {
    /**
     * @var int|float
     */
    private $foo;

    /**
     * @var int|float $foo
     */
    public function __construct($foo) {
        $this->foo = $foo;
    }

    /**
     * @var int|float bar
     * @return int|float
     */
    public function doSomethingWithMultipleTypes($bar) {
        return ($bar + $this->foo) * 2;
    }
}

$example = new Example(2);
echo $example->doSomethingWithMultipleTypes(3.0); // PHP will run this
echo $example->doSomethingWithMultipleTypes('tralala'); // PHP will also happily run this

PHP 8.0
#

Implementation example
#

class Example {
    private int|float $foo;

    public function __construct(int|float $foo) {
        $this->foo = $foo;
    }

    public function doSomethingWithMultipleTypes(float|int $bar): int|float {
        return ($bar + $this->foo) * 2;
    }
}

Type caveats
#

Void
#

Void cannot be used with another type as that makes no sense. A void function isn’t allowed to return anything

function foo(): void|null {} // This is invalid

false type
#

False is allowed to be used as a return type to support legacy code. There is no sane reason to do this for new code. This is bad form and imho shouldn’t have been included in the spec. The following code is therefore valid:

function tralala(): User|false {}

Inheritance
#

When extending another class, Union types can be added. The following is valid:

class A{
    public function foo(string|int $foo): string|int {}
}

class B extends A{
    public function foo(string|int|float $foo): string {}
}

However, you can’t change types. The following with generate an error:

class A{
    public function foo(string|int $foo): string|int {}
}

class B extends A{
    public function foo(string|float $foo): string|int {}
}

And that’s all I have to say about Unions in PHP8.