Take the State of PHP 2026 Survey →

Allow null and false as stand-alone types View as Markdown

Implemented (PHP 8.2)
Authors
George Peter Banyard, girgias@php.net
Date
2022-02-20
Version
0.3
Target
PHP 8.2
Implementation
https://github.com/php/php-src/commit/6039c07a3afd64a42c9b9f1ed994ca971db67a1e
Source
wiki.php.net/rfc/null-false-standalone-types

Vote

Accept Allow null and false as stand-alone types RFC? closed
Yes
38
No
0
38 voters
asgrim Yes 2022-03-13 22:22
ashnazg Yes 2022-03-16 14:16
bmajdak Yes 2022-03-12 19:15
colinodell Yes 2022-03-12 18:23
crell Yes 2022-03-12 18:08
cschneid Yes 2022-03-15 12:34
danack Yes 2022-03-13 00:28
daverandom Yes 2022-03-21 21:54
derick Yes 2022-03-17 11:00
didou Yes 2022-03-22 09:07
diegopires Yes 2022-03-17 14:39
galvao Yes 2022-03-13 11:30
girgias Yes 2022-03-12 17:30
irker Yes 2022-03-17 13:41
kalle Yes 2022-03-13 04:48
kguest Yes 2022-03-14 17:43
lcobucci Yes 2022-03-16 23:57
levim Yes 2022-03-17 15:52
marandall Yes 2022-03-12 18:18
mbeccati Yes 2022-03-21 16:39
mcmic Yes 2022-03-15 17:08
nicolasgrekas Yes 2022-03-15 08:29
nikic Yes 2022-03-20 20:56
ocramius Yes 2022-03-12 17:32
patrickallaert Yes 2022-03-15 11:20
petk Yes 2022-03-16 20:31
pollita Yes 2022-03-15 19:53
ramsey Yes 2022-03-18 23:32
reywob Yes 2022-03-12 18:29
santiagolizardo Yes 2022-03-25 17:00
seld Yes 2022-03-13 19:43
sergey Yes 2022-03-15 07:46
svpernova09 Yes 2022-03-12 17:34
tandre Yes 2022-03-15 18:10
theodorejb Yes 2022-03-12 20:15
trowski Yes 2022-03-14 18:37
villfa Yes 2022-03-17 20:20
weierophinney Yes 2022-03-12 17:34

Discussions on the mailing list

[RFC] Allow null and false as stand-alone types
by G. P. B. · 3 messages
[RFC] [VOTE] Allow null and false as stand-alone types
by G. P. B. · 8 messages

RFC text

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

Introduction

null corresponds to PHP's unit type, i.e. the type which holds a single value. false is a literal type of type bool.

It is currently not possible to use null as a type declaration on its own, as per its nature of it being the unit type, it cannot hold any information.

Moreover, false has traditionally been used instead of null to convey error state. This is the main reason why false was introduced as a literal type with the union type RFC1).

Motivation

There are a couple of motivations outlined below:

Type system completeness

PHP has added support for the top type mixed in PHP 8.0, the bottom type never in PHP 8.1, and support for composite types in PHP 8.0 with union types, and 8.1 with intersection types.

The inability to type the unit type in PHP is a deficiency which should be resolved.

Edge case with regards to the literal type false

The false literal type can only be used in union types, however this is not exactly correct as null|false is disallowed.

The only way to currently type this edge case is by using bool|null which gives the wrong impression that the value may also be true, making this type information less useful for humans and static analysers.

There are instances of this type declaration being needed within some of PHP's built-in functions, one example being gmp_random_seed().

This edge case might be expanded if literal types are added and cannot be used as stand-alone type, as a return type of 1 would also be disallowed.

Providing precise type information while satisfying LSP

A parent class might define a method as following: public function foo(): ?T, since PHP 7.4 covariance of return (and contravariance of parameter) types are supported , therefore it is possible for a child class to provide more precise type information if it always returns a value of type T: public function foo(): T.

However, the opposite isn't true, if the child method returns always null it must still use the original function signature and can only provide this information through documentation.

A method, from a built-in PHP class, which could benefit from declaring its return value as null is SplFileObject::getChildren().

The same applies to false where a userland extension for UConverter::transcode() might decided to always return falseand cannot currently type this properly.

Distinction between null and void

A function always returns a value in PHP, even if its return type is declared as void where NULLis the value returned. The union type RFC did not include support for null for the following reason:

The null type is only allowed as part of a union, and can not be used as a stand-alone type. Allowing it as a stand-alone type would make both function foo(): void and function foo(): null legal function signatures, with similar but not identical semantics. This would negatively impact teachability for an unclear benefit.

As explained previously, there are clear reasons as to why one may need to use null as a return type, as void is not a subtype of any other type and lives on its own in the type hierarchy.

Moreover, a function which has a void return type must only use return; whereas one with null must use return null;.

Proposal

Add support for using null and false as stand-alone type declarations, wherever type declarations are currently allowed.

class Nil {
    public null $nil = null;
 
    public function foo(null $v): null { /* ... */ *}
}
class Falsy {
    public false $nil = false;
 
    public function foo(false $v): false { /* ... */ *}
}

Redundancy of ?null

Trying to mark null as nullable will result in a compile time error, in line with PHP's current type resolving redundancy rules.

Reflection

Reflection support is as expected with the notable exception that null|false will produce a ReflectionUnionType instead of a ReflectionNamedType contrary to other null|T types.

A concrete case of how this looks like:

<?php
function dumpType(ReflectionUnionType $rt) {
    echo "Type $rt:\n";
    echo "Allows null: " . ($rt->allowsNull() ? "true" : "false") . "\n";
    foreach ($rt->getTypes() as $type) {
        echo "  Name: " . $type->getName() . "\n";
        echo "  String: " . (string) $type . "\n";
        echo "  Allows Null: " . ($type->allowsNull() ? "true" : "false") . "\n";
    }
}
 
function test1(): null|false { }
function test2(): ?false { }
 
 
dumpType((new ReflectionFunction('test1'))->getReturnType());
dumpType((new ReflectionFunction('test2'))->getReturnType());

Will produce the following output:

Type false|null:
Allows null: true
  Name: false
  String: false
  Allows Null: false
  Name: null
  String: null
  Allows Null: true
Type false|null:
Allows null: true
  Name: false
  String: false
  Allows Null: false
  Name: null
  String: null
  Allows Null: true

Example

We take an example from unit testing but it can be applied to other more general cases, where a class which implements an interface always returns null.

class User {}
 
interface UserFinder
{
    function findUserByEmail(): User|null;
}
 
class AlwaysNullUserFinder implements UserFinder
{
    function findUserByEmail(): null
    {
        return null;
    }
}

Currently it is not possible to write this code in PHP as it gives the error:

Fatal error: Null can not be used as a standalone type

This means that an incorrect User|null return definition needs to used for the findUserByEmail() method. That leads to further confusion as a static analyzer analysing that class will give a 'method can never return type User' error.

The same problem exists for interfaces that have a return type that is a union of false with another type.

Backward Incompatible Changes

This RFC does not contain any backwards incompatible changes.

Proposed PHP Version

Next minor version, i.e. PHP 8.2.

Proposed Voting Choices

As per the voting RFC a yes/no vote with a 2/3 majority is needed for this proposal to be accepted.

Voting started on 2022-03-12 and will end on 2022-03-26.

Vote: Accept Allow null and false as stand-alone types RFC? — Yes: 38 · No: 0 (closed)

Implementation

GitHub pull request: https://github.com/php/php-src/pull/7546

After the project is implemented, this section should contain

References

1)PHP RFC: Union Types 2.0