Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP type hints: is it possible to have a nullable union like ?string|array ...?

I'm on PHP 8.2.1. The following type hints work fine:

function abc(): ?string
function abc(): ?array
function abc(): string|array

...but a nullable union doesn't:

function abc(): ?string|array

>>> ParseError: syntax error, unexpected token "|", expecting "{"

Is there any workaround?

like image 257
Leszek Pachura Avatar asked Oct 22 '25 15:10

Leszek Pachura


2 Answers

Is there any workaround?

the so called nullable type in PHP (since 7.1) was an early way to allow to attribute allowing null as well to a single return type to laxen the rules. it was deemed useful when PHP started with return types as only a single type was allowed to be typed and returning null as well a common scenario.

function abc(): ?string
function abc(): ?array

since version 8.0 PHP has union types, that is with the pipe symbol ("|"), shown in your third definition:

function abc(): string|array

you could however likewise use union types when upgrading the earlier code to union types:

function abc(): null|string
function abc(): null|array

so as workaround, perhaps the nullable type is better classified as, and then it may become more clear that the union type of all three is what you're looking for (and not a workaround, at least in my book and IIUC):

function abc(): null|string|array

the nullable type notation with the question mark symbol ("?") survives in code-bases because it is much shorter and the usage is common - but incompatible with the pipe-notation of union types.

it may also have a bit of a renaissance with the release of PHP 8.4 as it deprecates using null as default value for a parameter given the parameters type does not include null. adding the type as an attribute to a parameter is supported since PHP version 5 for array and classes.

like image 114
hakre Avatar answered Oct 25 '25 07:10

hakre


The ?Foo syntax is considered a short-hand for the union type null|Foo (or Foo|null). It exists both because it was added before Union Types, and because it is a common case where a short-hand seems useful.

So in your example, all of these are valid:

function abc(): ?string {}
function abc(): ?array {}
function abc(): string|array {}
function abc(): null|string {}
function abc(): null|array {}
function abc(): null|string|array {}
function abc(): string|null {}
function abc(): array|null {}
function abc(): string|array|null {}

The short-hand can't be mixed with the full syntax, so these are not valid:

function abc(): ?string|array {}
function abc(): ?(string|array) {}
function abc(): ?string|?array {}

The design reasoning for this can be found in the RFC which introduced Union Types to PHP:

The null type is supported as part of unions, such that T1|T2|null can be used to create a nullable union. The existing ?T notation is considered a shorthand for the common case of T|null.

An earlier version of this RFC proposed to use ?(T1|T2) for nullable union types instead, to avoid having two ways of expressing nullability in PHP. However, this notation is both rather awkward syntactically, and differs from the well-established T1|T2|null syntax used by phpdoc comments. The discussion feedback was overwhelmingly in favor of supporting the T1|T2|null notation.

?T remains valid syntax that denotes the same type as T|null. It is neither discouraged nor deprecated, and there are no plans to deprecate it in the future. It is merely a shorthand alias for a particularly common union type.

like image 23
IMSoP Avatar answered Oct 25 '25 06:10

IMSoP