DEV Community

Cover image for The Difference Between ?: and ?? in PHP
Ash Allen
Ash Allen

Posted on • Originally published at ashallendesign.co.uk

The Difference Between ?: and ?? in PHP

Introduction

In PHP, I often see the ternary operator (?:) and null coalescing operator (??) being used interchangeably, but they actually serve different purposes.

In this article, we'll explore what both of these operators do and how they differ. We'll also look at some common gotchas that developers (myself included) have run into when using these operators.

The Ternary Operator (?:) in PHP

The ternary operator is a shorthand way of writing a ternary conditional statement.

For example, let's take a traditional if-else statement. We'll keep the examples in this article super simple purely for brevity.

Imagine we're trying to set a display name based on a provided name in a payload:

// Imagine this payload comes from an HTTP request.
$payload = [
    'name' => 'Ash',
    // ...
];

if ($payload['name']) {
    $displayName = $payload['name'];
} else {
    $displayName = 'Guest';
}

// $displayName is now set to 'Ash'
Enter fullscreen mode Exit fullscreen mode

We can rewrite this using a ternary condition like so:

$payload = ['name' => 'Ash'];

$displayName = $payload['name'] ? $payload['name'] : 'Guest'; // 'Ash'
Enter fullscreen mode Exit fullscreen mode

Which can then be further shortened using the ?: operator:

$payload = ['name' => 'Ash'];

$displayName = $payload['name'] ?: 'Guest'; // 'Ash'
Enter fullscreen mode Exit fullscreen mode

Now let's look at some examples of what $displayName would be set to based on different values of $payload['name'].

If the payload contains a non-empty string:

$payload = ['name' => 'Ash'];

$displayName = $payload['name'] ?: 'Guest'; // 'Ash'
Enter fullscreen mode Exit fullscreen mode

If the request payload contains an empty string or null:

$payload = ['name' => ''];

$displayName = $payload['name'] ?: 'Guest'; // 'Guest'
Enter fullscreen mode Exit fullscreen mode

If the payload contains null:

$payload = ['name' => null];

$displayName = $payload['name'] ?: 'Guest'; // 'Guest'
Enter fullscreen mode Exit fullscreen mode

If the payload contains false:

$payload = ['name' => false];

$displayName = $payload['name'] ?: 'Guest'; // 'Guest'
Enter fullscreen mode Exit fullscreen mode

However, what would happen if the payload array didn't have a name key at all?

$payload = [];

$displayName = $payload['name'] ?: 'Guest';
Enter fullscreen mode Exit fullscreen mode

Running the above code would result in the following exception being thrown:

ErrorException: Undefined array key "name"
Enter fullscreen mode Exit fullscreen mode

So we can see that the ternary operator checks for "truthiness" of the value. If the value is falsy (such as an empty string or null), it returns the value on the right side of the operator.

However, if the variable is not set at all, it will throw an error. And this is where I often see people get confused between the ?: and ?? operators. I've seen many developers expect that the ?: operator would handle unset variables gracefully, but it does not. So let's check out the null coalescing operator next.

The Null Coalescing Operator (??) in PHP

The null coalescing operator works in a similar way to the ternary operator, but it allows us to handle unset variables without throwing an error.

Let's take our previous example and update it to use the ?? operator instead:

$payload = ['name' => 'Ash'];

$displayName = $payload['name'] ?? 'Guest'; // 'Ash'
Enter fullscreen mode Exit fullscreen mode

The above code example is essentially the shorthand form of:

$payload = ['name' => 'Ash'];

$displayName = isset($payload['name']) ? $payload['name'] : 'Guest'; // 'Ash'
Enter fullscreen mode Exit fullscreen mode

As we can see, we can use the ?? operator in a similar way to the ?: operator, but it's checking whether the variable is set or not, rather than checking for "truthiness".

Let's see what happens if we try to access the name key when it is not set:

$payload = [];

$displayName = $payload['name'] ?? 'Guest'; // 'Guest'
Enter fullscreen mode Exit fullscreen mode

In the code example, we can see that when the name key is not set in the payload array, the ?? operator returns the value on the right side of the operator without throwing an error.

This can be really useful when working with data that's passed to you from external sources, such as API requests or user input, where you can't always guarantee that certain keys will be present.

Another key difference between the ?? and ?: operators is that the ?? operator only checks for null or unset values, whereas the ?: operator checks for "truthiness". Let's take this example:

$payload = ['name' => false];

// Using the ternary operator:
$displayName = $payload['name'] ?: 'Guest'; // 'Guest'

// Using the null coalescing operator:
$displayName = $payload['name'] ?? 'Guest'; // false
Enter fullscreen mode Exit fullscreen mode

As we can see in the example above, when the name key is set to false, the ?: operator returns 'Guest', whereas the ?? operator returns false. This is something you'll want to keep in mind when deciding which operator to use.

Common Gotcha with the Null Coalescing Operator

A common gotcha I see developers run into (and have done myself many times) is accidentally hiding errors when using the ?? operator.

For example, let's say you have an API request payload that is expected to contain a first_name key, but you accidentally misspell it as frist_name:

$payload = ['first_name' => 'Ash'];

$firstName = $payload['frist_name'] ?? 'Guest'; // 'Guest'
Enter fullscreen mode Exit fullscreen mode

At first glance, this code might seem okay since it doesn't throw any runtime errors. However, we will always get 'Guest' as the value of $firstName. Of course, this should typically be caught during manual and automated testing. But these things can sometimes slip through the cracks, especially in larger codebases.

Alternatively, if we had used the ternary operator instead, we would have gotten an error when trying to access the unset first_name key, which would have alerted us to the typo:

$payload = ['first_name' => 'Ash'];

$firstName = $payload['frist_name'] ?: 'Guest';

// ErrorException: Undefined array key "first_name"
Enter fullscreen mode Exit fullscreen mode

Should You Use the Ternary or Null Coalescing Operator?

Both operators have valid use cases and are valuable tools in your PHP arsenal.

If you always know that a value will be available (i.e. it won't be unset), and you want to check for "truthiness", then the ternary operator (?:) is a good choice.

However, if you want to handle unset variables gracefully, or you only want to check for null or unset values, then the null coalescing operator (??) might be the better option.

As you'd imagine, the decision of which operator to use often comes down to the specific use case and the data you're working with. So you'll likely use a mixture of both operators in your codebase.

Conclusion

In this article, we've quickly explored the differences between the ?: (ternary) and ?? (null coalescing) operators in PHP.

If you enjoyed reading this post, you might be interested in checking out my 220+ page ebook "Battle Ready Laravel" which covers similar topics in more depth.

Or, you might want to check out my other 440+ page ebook "Consuming APIs in Laravel" which teaches you how to use Laravel to consume APIs from other services.

If you're interested in getting updated each time I publish a new post, feel free to sign up for my newsletter.

Keep on building awesome stuff! 🚀

Top comments (0)