PHP 8.1: never
return type
never
is a new return type added in PHP 8.1.
A function/method that is declared with the never
return type indicates that it will never return
a value, and always throws an exception or terminates with a die
/exit
call.
never
return type is similar to the existing void
return type, but the never
type guarantees that the program will terminate or throw. In other words, a function/method declared never
must not call return
at all, not even in the return;
form.
function redirect(string $url): never {
header('Location: ' . $url);
exit();
}
The goal of the never
return type is to indicate and enforce a function that prevents the rest of the called code from being executed. IDEs, and PHP itself can recognize functions with the never
return types, and safely assume that the rest of the code in scope will not run.
function redirect(string $url): never {
header('Location: ' . $url);
exit();
}
redirect('Test'); // The rest of the code is GUARANTEED to not continue.
do_something_else();
A function/method with the never
return type must prevent the rest of the code in scope from being executed. This is achieved by either terminating the request (die
/exit
), or throwing an exception.
If function/method with the never
return type does not throw an exception, or terminate the program, PHP will throw a TypeError
exception:
function dispatch(string $message): never {
echo $message;
}
dispatch('test');
TypeError: dispatch(): never-returning function must not implicitly return
On the other hand, if a never
-declared function calls return
, it will throw a TypeError
exception. This is enforced at the call-time, rather than at the parsing time.
function foo(): never {
return;
}
foo();
Fatal error: A never-returning function must not return in ... on line 2
The original RFC proposed to use
noreturn
for this purpose. A secondary vote in the RFC contestednoreturn
vsnever
, andnever
was elected.
never
is a return-type
Similar to void
, never
is a return type. Using never
in a parameter or a property type is not allowed.
function foo(never $a) {}
Fatal error: never cannot be used as a parameter type in ... on line ...
Using never
as a class property type causes a similar fatal error:
class Foo {
private never $bar;
}
Fatal error: Property Foo::$bar cannot have type never in ... on line 3
never
cannot be used in a Union Type
Using never
in a Union Type is not allowed. This is similar to how the void
type is enforced as well.
function foo(): never|string {}
Fatal error: never can only be used as a standalone type in ... on line 3
never
vs void
The new never
return type and void
return type share many common traits. They both communicate that the function/method will never return a value. However, the never
type also enforces that an exception is thrown, or the program is terminated.
void
andnever
both are return types. They cannot be used as parameter types or property types.- Using
void
ornever
The difference with void
and never
is that void
allows calling return
without an explicit value. i.e. return;
. However, calling return
(even without a value) is not allowed at all in a never
-declared function.
Variance with never
never
is a "bottom" type. This effectively means that a class method with never
return type cannot change the return type to any other type, because there is no other smaller type than never
.
class Foo {
public function test(): string {}
}
class FooBar extends Foo{
public function test(): never {}
}
The snippet above is valid, because never
is a bottom type. With Liskov Substitution Principle in PHP, changing the return type with a subset (smaller type) is allowed.
Note that with void
and never
, never
is the smaller type. A method that is declared void
can be extended with a method that declares never
as the return type.
class Foo {
public function test(): never {}
}
class FooBar extends Foo{
public function test(): string {}
}
Fatal error: Declaration of FooBar::test(): string must be compatible with Foo::test(): never in ... on line ...
FooBar::test()
method is not allowed to declare the return type as string
, because it is a wider type than never
.
Backwards Compatibility Impact
never
is a new return type in PHP 8.1. It carries certain engine changes to enforce a function call declared never
follows the rules. This behavior cannot be brought-back to older PHP versions using user-land PHP code.
Further, never
becomes a reserved keyword in PHP, and using never
for function names, class names, whole namespace, etc. will cause parse errors or other types of fatal errors.
@return noreturn
Doc Annotations
PHP static analysis tools such as Psalm and PHPStan support a return type noreturn
that infers the same data. In fact, the never
type was proposed to PHP by the authors of Psalm and PHPStan tools.
With the never
type supported in PHP, it is now possible to remove existing Doc Block annotations if the minimum PHP version is set to PHP >= 8.1.
/**
-* @return noreturn
*/
-function redirect(string $url): void {
+function redirect(string $url): never {
header('Location: ' . $url);
exit();
}