Take the State of PHP 2026 Survey →

Nullable Types View as Markdown

Implemented (PHP 7.1)
Authors
Levi Morrison levim@php.net
Date
2014-04-10
Version
1.0
Source
wiki.php.net/rfc/nullable_types

Votes

Accept explicitly nullable types? (2/3 affirmative required) closed
Yes
41
No
2
43 voters
ajf Yes 2016-05-10 20:20
beberlei Yes 2016-05-11 21:53
bishop Yes 2016-05-10 18:18
bwoebi No 2016-05-10 15:39
colinodell Yes 2016-05-10 21:54
daverandom Yes 2016-05-10 15:29
davey Yes 2016-05-12 11:34
derick Yes 2016-05-10 19:09
dmitry Yes 2016-05-10 17:53
francois Yes 2016-05-10 22:41
galvao Yes 2016-05-22 10:19
guilhermeblanco Yes 2016-05-10 17:31
hywan Yes 2016-05-13 20:58
jhdxr Yes 2016-05-16 12:44
jwage Yes 2016-05-17 03:27
kalle Yes 2016-05-10 21:44
kguest Yes 2016-05-12 20:47
klaussilveira Yes 2016-05-10 16:27
lcobucci Yes 2016-05-11 06:06
lstrojny Yes 2016-05-11 22:34
malukenho Yes 2016-05-11 09:31
mariano Yes 2016-05-10 22:09
mbeccati Yes 2016-05-11 04:30
mcmic Yes 2016-05-11 02:49
mfonda Yes 2016-05-20 15:09
mgocobachi Yes 2016-05-11 20:22
mike Yes 2016-05-10 21:09
nikic Yes 2016-05-10 15:25
ocramius Yes 2016-05-10 16:40
omars Yes 2016-05-16 10:46
peehaa Yes 2016-05-10 15:38
philstu Yes 2016-05-13 14:23
pierrick Yes 2016-05-11 01:58
pollita Yes 2016-05-10 18:00
salathe Yes 2016-05-16 11:56
sammyk Yes 2016-05-20 14:56
stas No 2016-05-10 22:56
svpernova09 Yes 2016-05-16 00:54
till Yes 2016-05-11 22:46
tpunt Yes 2016-05-10 19:59
trowski Yes 2016-05-10 17:41
weierophinney Yes 2016-05-10 20:46
zimt Yes 2016-05-11 12:31
Merge which features? (majority wins) closed
Both nullable parameter and return types
44
Only nullable return types
1
45 voters
ajf Both nullable parameter and return types 2016-05-10 20:20
beberlei Both nullable parameter and return types 2016-05-11 21:53
bishop Both nullable parameter and return types 2016-05-10 18:19
bwoebi Both nullable parameter and return types 2016-05-10 15:38
colinodell Both nullable parameter and return types 2016-05-10 21:54
danack Both nullable parameter and return types 2016-05-10 19:00
daverandom Both nullable parameter and return types 2016-05-10 15:29
davey Both nullable parameter and return types 2016-05-12 11:35
derick Both nullable parameter and return types 2016-05-10 19:09
dragoonis Both nullable parameter and return types 2016-05-11 00:14
francois Both nullable parameter and return types 2016-05-10 22:41
galvao Both nullable parameter and return types 2016-05-22 10:19
guilhermeblanco Both nullable parameter and return types 2016-05-10 17:30
hywan Both nullable parameter and return types 2016-05-13 20:58
jhdxr Both nullable parameter and return types 2016-05-16 12:44
jwage Both nullable parameter and return types 2016-05-17 03:27
kalle Both nullable parameter and return types 2016-05-10 21:43
kguest Both nullable parameter and return types 2016-05-12 20:47
kinncj Both nullable parameter and return types 2016-05-12 18:10
klaussilveira Both nullable parameter and return types 2016-05-10 16:27
lstrojny Both nullable parameter and return types 2016-05-11 22:34
malukenho Both nullable parameter and return types 2016-05-11 09:31
marcio Both nullable parameter and return types 2016-05-10 19:00
mariano Both nullable parameter and return types 2016-05-10 22:10
mcmic Both nullable parameter and return types 2016-05-11 02:49
mfonda Both nullable parameter and return types 2016-05-20 15:10
mgocobachi Both nullable parameter and return types 2016-05-11 20:22
mike Both nullable parameter and return types 2016-05-10 16:52
nikic Both nullable parameter and return types 2016-05-10 15:25
ocramius Both nullable parameter and return types 2016-05-10 16:40
omars Both nullable parameter and return types 2016-05-16 10:47
peehaa Both nullable parameter and return types 2016-05-10 15:38
philstu Both nullable parameter and return types 2016-05-13 14:23
pierrick Both nullable parameter and return types 2016-05-11 01:57
pollita Both nullable parameter and return types 2016-05-10 18:00
rdohms Both nullable parameter and return types 2016-05-11 21:45
salathe Both nullable parameter and return types 2016-05-16 11:55
sammyk Both nullable parameter and return types 2016-05-20 14:56
stas Only nullable return types 2016-05-10 22:56
svpernova09 Both nullable parameter and return types 2016-05-16 00:55
till Both nullable parameter and return types 2016-05-11 22:46
tpunt Both nullable parameter and return types 2016-05-10 19:59
trowski Both nullable parameter and return types 2016-05-10 17:42
weierophinney Both nullable parameter and return types 2016-05-10 20:46
zimt Both nullable parameter and return types 2016-05-11 12:31

Discussions on the mailing list

Improving PHP's type system
by Levi Morrison · 94 messages
[RFC] Nullable Types
by Levi Morrison · 25 messages
[RFC] Pre-vote notice for Nullable Types
by Levi Morrison · 7 messages
[RFC][VOTE] Nullable Types
by Levi Morrison · 16 messages
my concept ( new PDO FETCH MODE )
by Csonka Titus · 2 messages

RFC text

Copied from wiki.php.net, last synchronized Oct 13, 2026 11:51 UTC

Introduction

It is common in many programming languages including PHP to allow a variable to be of some type or null. This null often indicates an error or lack of something to return. This can already be done using PHP's dynamic type system by omitting type declarations. It can also be done for parameters in PHP by using a default parameter of null. However, this does not work for return types which do not have a concept of a default value. This RFC proposes a unified way to add nullable types to both parameters and returns.

Proposal

This proposal adds a leading question mark symbol (?) to indicate that a type can also be null. Nullable types can be formed from any currently permitted type. Nullable types are permitted anywhere type declarations are allowed but are subject to some inheritance rules which are outlined later in the RFC.

Here are a few examples to demonstrate basic functionality:

function answer(): ?int  {
    return null; //ok
}
 
function answer(): ?int  {
    return 42; // ok
}
 
function answer(): ?int {
    return new stdclass(); // error
}
function say(?string $msg) {
    if ($msg) {
        echo $msg;
    }
}
 
say('hello'); // ok -- prints hello
say(null); // ok -- does not print
say(); // error -- missing parameter
say(new stdclass); //error -- bad type

Return Types

When subtyping a return type the nullability can be removed by a subclass, but it cannot be added:

interface Fooable {
    function foo(): ?Fooable;
}
interface StrictFooable extends Fooable {
    function foo(): Fooable; // valid
}
interface Fooable {
    function foo(): Fooable;
}
interface LooseFooable extends Fooable {
    function foo(): ?Fooable; // invalid
}

Parameter Types

The nullable type cannot be removed in a sub-class; it can be added if not present in a super-class. This behavior is consistent with the Liskov substitution principle.

// Valid use: loosening the nullable marker in a parameter:
interface Fooable {
    function foo(Fooable $f);
}
interface LooseFoo extends Fooable {
    function foo(?Fooable $f);
}
// Invalid use: tightening the nullable marker in a parameter:
interface Fooable {
    function foo(?Fooable $f);
}
interface StrictFoo extends Fooable {
    function foo(Fooable $f);
}

Default Values

Differences from default values

Parameters with a nullable type do not have a default value. If omitted the value does not default to null and will result in an error:

function f(?callable $p) {}
f(); // invalid; function f does not have a default

Relationship with default values

PHP's existing semantics allow giving a null default value for a parameter to make it nullable and optional:

function foo_default(Bar $bar = null) {}
 
foo_default(new Bar); // valid
foo_default(null); // valid
foo_default(); // valid

This existing behaviour is not changed by this RFC. The new nullable type feature offers a subset of the functionality of = null with both making a parameter nullable but only = null making a parameter optional and have a default value:

function foo_nullable(?Bar $bar) {}
 
foo_nullable(new Bar); // valid
foo_nullable(null); // valid
foo_nullable(); // INVALID!

As = null offers a superset of ?'s functionality, it could be said that = null implies ?. However, it is perfectly legal to use both to make a parameter's nullability explicit:

function foo_both(?Bar $bar = null) {}
 
foo_both(new Bar); // valid
foo_both(null); // valid
foo_both(); // valid

Because a parameter with = null is a superset of ?, you can use a parameter with a default value of null where a nullable type existed in the parent.

interface Contract {
    function method(?Foo $foo): bool;
}
 
class Implementation implements Contract {
    function method(?Foo $foo = null): bool {
        return is_null($foo);
    }
}

The reverse is not true, however: you cannot use only a nullable type where a default value existed in the parent, because the parameter is no longer optional.

PHP Version

This RFC targets PHP 7.1.

Voting Choices

The vote for this RFC is split into two votes. One vote will be for accepting the idea of explicitly nullable types with the short-hand syntax. The second vote determines whether to merge only nullable return types or to also merge nullable parameter types as well.

Voting began Tuesday, May 10th, 2016 and will close on Friday, May 20th, 2016.


Vote: Accept explicitly nullable types? (2/3 affirmative required) — Yes: 41 · No: 2 (closed)


Vote: Merge which features? (majority wins) — Both nullable parameter and return types: 44 · Only nullable return types: 1 (closed)

Patches and Tests

The pull request for this RFC is here: https://github.com/php/php-src/pull/1893.

RFC Impact

To Backward Compatibility

There is a backwards compatibility break in certain cases. This was previously fixed as a bug but it was decided that because of the BC break that it would be pushed to this RFC. See bug 72119 for more info on the BC break.

This BC break is to reject parameter covariance for nullable types:

interface Fooable {
    function foo(?Fooable $f);
}
interface StrictFoo extends Fooable {
    // Invalid; parent type allows null so subtype must also allow it
    function foo(Fooable $f);
}

However, it breaks this code:

interface Fooable {
    function foo(array $f = null);
}
interface LooseFoo extends Fooable {
    function foo(array $f = []);
}

Such code should be modified to also allow null:

interface LooseFoo extends Fooable {
    function foo(?array $f = []);
}

Note that more handling is probably necessary to make the code robust, but this small change is sufficient for any previously working code to continue to work.

To Existing Extensions

Only extensions that deal with the AST need to be updated. They should be aware of the ZEND_TYPE_NULLABLE attribute that gets set when a ? is present.

To Union Types

Nullable types are a special case of union types where there only two types in the union, one of which is always null. If the union_types RFC is accepted then ?Foo will be exactly equivalent to Foo | Null. The union types RFC will be responsible for intersecting decisions, such as whether ? can be used in conjunction with other union types.

Unaffected PHP Functionality

This RFC does not deprecate the default value syntax. While there is some overlap of features between it and this RFC, they serve different purposes. As such, the default value syntax will remain.

Future Scope

  1. Full union types

Implementation

After the project is implemented, this section should contain

  1. the version(s) it was merged to
  2. a link to the git commit
  3. a link to the PHP manual entry for the feature

References

  1. Discussion on mailing list
  2. Background for multiple type enhancements: http://news.php.net/php.internals/92252