never Return Type — Functions That Never Return
PHP 8.1 added the never return type for functions that unconditionally throw an exception or call exit(). It's a small addition with outsized benefits for static analysis and control flow clarity.
function redirect(string $url): never
{
header('Location: ' . $url);
exit();
}
function abort(int $code, string $message): never
{
throw new HttpException($code, $message);
}
// Static analysers understand the control flow
function findOrFail(int $id): User
{
$user = User::find($id);
if ($user === null) {
abort(404, 'User not found'); // analyser knows: never returns
}
return $user; // analyser knows: $user is User here, not User|null
}
Before never, static analysers had no way to know that abort() or redirect() would halt execution. They'd warn about missing return statements, or fail to narrow types after an early exit. With never, the entire call graph is understood: dead code after these calls is detected, and type narrowing works across function boundaries.
// PHPStan / Psalm understand this is unreachable:
function process(string|null $value): string
{
if ($value === null) {
abort(400, 'Required'); // never
}
return strtoupper($value); // $value is string here — no null check needed
}
Significance: Control Flow Clarity
never makes implicit contracts explicit. Helper functions that always throw or redirect were always present in PHP codebases — now they carry their contract in the type signature, where static analysers and future readers can rely on it.