Nullable Types

In the example shown below, the int $x = null type declaration means that parameter $x is of type int, nullable, optional, and has the default value null. When the parameter is omitted, then its value will be null inside the function’s body. When it is not omitted, then its value must either be of type int or null.

function f(int $x = null)
{
    var_dump($x);
}

f();
f(null);
f(1);
f('');

Executing the code shown above will print the output shown below:

NULL
NULL
int(1)

Fatal error: Uncaught TypeError:
Argument 1 passed to f() must be of the type integer, string given

It is possible to declare parameters to be nullable but not optional. To do this, simply prefix a type declaration with a question mark:

function f(?int $x)
{
    var_dump($x);
}

f(null);
f(1);
f();

Executing the code shown above will print the output shown below:

NULL
int(1)

Fatal error: Uncaught TypeError:
Argument 1 passed to f() must be of the type integer, none given

For compliance with the Liskov Substitution Principle, the nullability of a parameter should not be removed in a child class:

class ParentClass
{
    public function m(?int $x)
    {
    }
}

class ChildClass extends ParentClass
{
    public function m(int $x)
    {
    }
}

Executing the code shown above will print the output shown below:

Warning: Declaration of ChildClass::m(int $x) should be compatible
with ParentClass::m(?int $x) ...

A child class should not accept less input values than the parent class. In this example, when passing null for parameter $x, you cannot substitute ChildClass for ParentClass:

$o = new ChildClass;
$o->m(null);

Passing null yields a type error at runtime:

Warning: Declaration of ChildClass::m(int $x) should be compatible
with ParentClass::m(?int $x) ...

Fatal error: Uncaught TypeError: Argument 1 passed to ChildClass::m()
must be of the type integer, null given, called in ...

Nullability of a parameter can be added in a child class, though, when the parameter’s type declaration is not nullable in the parent class. This means that a child class accepts more input values than the parent class.