In PHP 8.1 and later, what is the difference between the void and never return types, and when is each used?
answer
- void returns, but with no value
- return; allowed, return null; not
- never: throw, exit or loop forever
- implicit return from never is TypeError
- both standalone; never since 8.1
basics
~20 svoid means the function returns normally but hands back no value, so callers see null. never, added in PHP 8.1, means the function does not return at all: it must throw, exit or loop forever, and falling off its end throws TypeError.
solid answer
~40 s`void` (PHP 7.1) says the function **completes without a value**: it may use a bare `return;` or no return at all, but `return null;` or any other value is a compile error, and a caller reading the result gets `null`. `never` (PHP 8.1) says control **never comes back** to the caller: the function must throw, call `exit`, or loop forever. `return;` inside a `never` function is a compile error, and reaching the end of its body throws `TypeError` at runtime. Both are return-only and must stand alone — no `?void`, no `never|int`. Use `void` for commands such as `logFine()`, and `never` for helpers like `redirect()` that exit or `fail()` that always throws, so readers and static analysers know the code after the call is unreachable.
code
php · 18 lines<?php
declare(strict_types=1);
function logFine(int $cents): void
{
if ($cents === 0) {
return; // bare return is allowed
}
error_log("fine: $cents");
}
function redirectToLogin(): never
{
header('Location: /login');
exit; // removing this line makes PHP throw TypeError
}
var_dump(logFine(0)); // NULLgo deeper
Recall that void returns with no value and never does not return at all. Know that return null; is not allowed in a void function.
Explain the rules: bare return in void, no return in never, the runtime TypeError when never falls through, and why both must stand alone.
Use never on throw and redirect helpers so analysers see unreachable code, and catch fall-through paths in tests because PHP only reports them when they run.
Decide how far a codebase should encode control flow in types: never on terminators, void on commands, and where exceptions stay undeclared paths.
## Two return types that say "no useful value" Both `void` and `never` are declared where a return type goes, and both mean a caller gets nothing useful back. They make very different promises, though: - **`void`** (added in PHP 7.1): the function **returns normally**, it just does not return a value. - **`never`** (added in PHP 8.1): the function **does not return** at all. Control does not come back to the line after the call. In type-theory terms `never` is the **bottom type**: a type with no values, which is why the manual describes it as a subtype of every other type. ## Rules for void 1. A `void` function may end without a `return`, or use a bare `return;` to leave early. 2. Returning a value is a **compile error**. Even `return null;` is rejected, with a message that suggests the fix: `A void function must not return a value (did you mean "return;" instead of "return null;"?)`. 3. The caller can still read the result, and it is `null`. Nothing stops `$x = logFine($f);`, it is just pointless. 4. `void` must stand alone: `?void` or `void|int` fails with `Void can only be used as a standalone type`. 5. `void` cannot be a parameter type: `void cannot be used as a parameter type`. ## Rules for never 1. The function must end by **throwing**, by calling **`exit`/`die`**, or by **never terminating** (an endless loop, such as a worker that blocks forever). 2. Any `return` statement, even a bare `return;`, is a **compile error**: `A never-returning function must not return`. 3. If execution **falls off the end** of the body — a code path the author forgot — PHP throws `TypeError` at runtime: `redirectToLogin(): never-returning function must not implicitly return`. This is checked when it happens, not at compile time, because the compiler cannot prove every path throws. 4. `never` must stand alone: `never can only be used as a standalone type`, and it is not allowed as a parameter type. ## Side by side | | `void` | `never` | |---|---|---| | Available since | PHP 7.1 | PHP 8.1 | | Control returns to caller | yes | no | | `return;` | allowed | compile error | | `return $value;` | compile error | compile error | | Reaching end of body | fine, caller gets `null` | `TypeError` at runtime | | Nullable or in a union | not allowed | not allowed | | Typical use | commands and side effects | throw helpers, redirect-and-exit, endless workers | ## Why never earns its place Before PHP 8.1, a helper that always threw had to be declared `void` or left without a return type. Readers and tools then had to assume the call might return, so code after it looked reachable: ```php <?php declare(strict_types=1); function failFine(string $reason): never { throw new DomainException($reason); } function fineFor(int $days): int { if ($days < 0) { failFine('negative days'); } return $days * 25; } ``` With `never`, a static analyser knows the `if` branch cannot fall through, and a reviewer knows `failFine()` is a terminator, not a logger. The same applies to a redirect helper that sends a `Location` header and then calls `exit` — declaring it `never` documents, and at runtime enforces, that the script stops there. ## The static return type A third return-only declaration, `static`, was added in PHP 8.0. It is a type meaning "an instance of the class the method was called on", which is what fluent builders and named constructors in a class hierarchy want to promise. Like `void` and `never` it cannot be used for parameters. How `static` resolves at call time is late static binding, a separate topic. ## Choosing between them - A method that changes state and reports nothing — `recordPayment()`, `logFine()` — is `void`. - A function whose job is to stop the current flow — throw a domain error, redirect and exit, run until killed — is `never`. - If a function sometimes returns and sometimes throws, it is neither: give it its real return type and let the throw be an exceptional path.
- In PHP, why is return null; rejected in a void function when calling that function yields null anyway?Because `void` declares that the function produces no value, and `return null;` is returning one. The compile error even suggests `return;` instead. The caller seeing `null` is just what PHP gives for any call that returns nothing; it is not a value the function chose. If `null` is meaningful, the right declaration is `null` or `?T`, not `void`.
- In PHP 8.1+, is it a compile-time or runtime error when a never function can reach the end of its body?Runtime. The compiler rejects any explicit `return` in a `never` function, but it cannot prove that every path throws or exits. If execution actually reaches the end, PHP throws `TypeError` with `never-returning function must not implicitly return`. A path that is never taken never triggers it, so tests and static analysis are what catch the forgotten branch.
- In PHP 8.0+, what does a static return type on a method promise?That the method returns an instance of the class it was called on, not just the declaring class, which suits fluent setters and named constructors in a hierarchy. `static` is return-only: it cannot type a parameter. The return check verifies the object's class at runtime like any other class type.
void is a courier who delivers the parcel and comes back empty-handed; never is a courier on a one-way trip who either stays at the destination or reports an accident, but does not come back to the depot.
saying these in an interview costs you the question
- Says a void function may end with return null; since callers see null anyway.
- Thinks never is just another name for void.
- Believes a never function may use a bare return; to leave early.
- Claims PHP proves at compile time that every path of a never function throws.
- Writes ?void or never|int as a valid return declaration.