PHP 7.1: Nullable Types and the Void Return Type
PHP 7.1's nullable type declarations and void return type make function signatures more readable and precise.
PHP 7.0 introduced scalar type declarations and return types. I still remember noticing how immediately readable function signatures became when I first used that release. Less than six months later, PHP 7.1 arrived with two small but practically impactful additions that changed how I write code every day: nullable types and the void return type.
These changes are bigger than they look. Being able to glance at a signature and answer “can this function return null?” or “can this parameter be empty?” without opening the source code is just as valuable as writing pre-checks.
Why nullable types were necessary
In PHP 7.0 you could write a signature like this:
function findUser(int $id): User
{
// ...
}
But what if the user isn’t found? What if you need to return null? In 7.0 there was no way to express that possibility in the return type declaration — you either ignored nullability or fell back to something vague like mixed.
PHP 7.1 closed that gap with a question mark:
function findUser(int $id): ?User
{
$row = $this->db->find($id);
return $row ? new User($row) : null;
}
Anyone reading the signature now immediately knows: “this function returns either a User object or null.” The same syntax applies to parameters:
function greet(?string $name): string
{
return 'Hello, ' . ($name ?? 'guest');
}
Here $name may be omitted entirely or passed as null. The function handles both cases and says so explicitly in its signature.
The void return type
When a function truly returns nothing, you can now declare that with void:
function logActivity(string $message): void
{
file_put_contents('/var/log/app.log', $message . PHP_EOL, FILE_APPEND);
}
If you write return $something; inside a void-declared function, you get a TypeError. A bare return; or no return statement at all is fine — both are valid.
What does this give you? It lets someone reading the code skip the mental question “what happens if I try to assign this function’s return value somewhere?” I call this putting intent into the signature — not documentation, but a compile-time guarantee.
A real-world scenario
Consider order lookup and status update functions in an e-commerce project:
function findOrder(int $orderId): ?Order
{
return Order::find($orderId); // Eloquent returns null when not found
}
function updateOrderStatus(Order $order, string $status): void
{
$order->status = $status;
$order->save();
}
findOrder can return null — the calling code knows this and understands it must perform a null check. updateOrderStatus produces only a side effect with no return value — the signature says so.
You do not need to look inside either function to understand its behavior. When you are working with teammates or reading your own code three months later, that difference matters.
The difference between a nullable type and a default value
A subtle point worth calling out: ?string $name and string $name = '' are not the same thing. The first lets the parameter accept null or be omitted entirely; the second does not accept null — it expects a string, and falls back to an empty string if nothing is provided. The semantic difference is meaningful: “this value is unknown” versus “this value is absent but has a default.” Using the two interchangeably can lead to unexpected behavior down the line. A nullable type says “we need to know when this value is genuinely missing”; a default value says “use this if it is not supplied.”
A small addition, a significant gain
Both of these PHP 7.1 features can be added to existing code without a major refactor. I have made it a habit to add a nullable type or void to every new function I write, because a signature that “doesn’t lie” delivers a kind of correctness that outlasts everything else in the codebase.
Wherever you would reach for mixed or silently return null without declaring it, writing ?Type instead is a small kindness — to yourself and to whoever reads the code next.
Comments
Sign in with your GitHub account to join the discussion. Comments are stored in GitHub Discussions.