rfc:nullable_intersection_types

This is an old revision of the document!


PHP RFC: Nullable Intersection types

Introduction

Intersection types as currently accepted for PHP 8.1 are not nullable. This RFC proposes to make them so.

Proposal

Intersection types as currently accepted for PHP 8.1 are not nullable: when one uses X&Y as a type on a property, an argument or a return value, there is no syntax to declare them as also accepting the null value. This means that it is required to use the null-pattern where default values are needed for properties and for optional arguments. For return-types, a null-object must be returned and potentially detected using a custom check.

While useful in some cases, the null-pattern is not common in PHP. One reason might be that it requires quite some boilerplate (the implementation of the null-object's class), but the most likely reason is that the null value works just great instead, with zero extra code to write.

This RFC proposes to add a syntax to the language to declare that a type accepts both an intersection or null. The possible syntax choices are discussed below. Using the longest syntax that has been proposed so far as an example, this PR aims at allowing the following piece of code:

class Foo
{
    public (X&Y)|null $bar;
 
    function setBar((X&Y)|null $bar = null): (X&Y)|null
    {
        return $this->bar = $bar;
    }
}

Rationale

When PHP 7.0 introduced scalar types, it was obvious that the special null type was missing as a way to declare the empty state of an argument, property, or return value. PHP 7.1 added the ?foo syntax to declare nullability and scalar types gained much broader adoption. This lesson from history tells us that the nullable type is special and very much needed in PHP.

As for scalars, nullable intersection types would make optional arguments/properties/return-values trivial to implement. It would also make them consistent with the other type declarations.

For userland, if this nullable capability were added to a later version of PHP, making a parameter nullable later would cause a BC break (or force a major version bump when using semver.) This is of course because of LSP rules.

From an implementation point of view, the linked patch is trivial: the source of PHP already implements all the required logic to deal with variance/covariance rules related to the null type. The patch is only a matter of adding a syntax to tell the engine about nullability and everything else works already.

For all these reasons, this RFC proposes to make intersection types nullable, and to make them so right away in PHP 8.1.

Future Scope

Syntax choices

TBD

Proposed PHP Version(s)

PHP 8.1.

Proposed Voting Choices

As per the voting RFC, the first question requires a 2/3 majority for this proposal to be accepted:

  • Make intersection types nullable: yes / no
  • Preferred syntax: “?” prefix / “|null” suffix
  • If “?” wins, brackets should be: mandatory “?(Y&Y)” / not needed “?X&Y” / both styles should work
  • If “|null” wins, brackets should be: mandatory “(Y&Y)|null” / not needed “X&Y|null” / both styles should work

Patches and Tests

See https://github.com/php/php-src/pull/7259

Patch will be updated according to the syntax decided by the vote.

Implementation

After the project is implemented, this section should contain

  1. the version(s) it was merged into
  2. a link to the git commit(s)
  3. a link to the PHP manual entry for the feature
  4. a link to the language specification section (if any)

References

rfc/nullable_intersection_types.1626970288.txt.gz · Last modified: 2021/07/22 16:11 by nicolasgrekas