# 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.

- Published: 2017-01-01
- Category: Languages
- Tags: PHP
- Reading time: 3 min read
- Source: https://www.muhammetsafak.com.tr/en/blog/php-7-1-nullable-types-and-void-return-type/
- Language: en-US
- Author: Muhammet Şafak

---
[PHP 7.0 introduced scalar type declarations and return types](/en/blog/scalar-type-declarations-and-return-types-in-php-7). 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:

```php
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:

```php
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:

```php
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`:

```php
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:

```php
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.
