PHP Check for Empty Values: "!" vs "is_null" vs "isset"

Have you ever wondered what's the difference between !$var and is_null($var)? What about isset($var)? Let's discuss those with a practical example.

Let's jump into an example function that takes four different arguments and returns HTML text.

All those parameters are optional, so inside the function, we're checking if they are passed or not with the ! operator.

function formatUser(
?User $user,
?bool $isVip,
?string $nickname,
?array $badges
): string {
$user = ! $user ? 'No email present.' : $user->email;
$isVip = ! $isVip ? '' : 'checked';
$nickname = ! $nickname ? 'Anonymous' : $nickname;
if (! $badges) {
$badges = ['Not assigned'];
$formattedBadges = '';
foreach ($badges as $badge) {
$formattedBadges .= '<div class="badge">' . $badge . '</div>';
return sprintf('<div class="user-row">
<div>VIP <input type="checkbox" disabled %s></div>
<div class="flex space-x-0.5">%s</div>

And then, we're trying to use that function with four different cases. The Blade View part of using that function looks like this:

<div class="p-6 text-gray-900">
{!! formatUser(User::find(1), true, fake()->words(asText: true), null) !!}
{!! formatUser(User::find(2), false, null, null) !!}
{!! formatUser(User::find(3), false, '0', null) !!}
{!! formatUser(null, true, 'Some nickname', ['Category Z', 'Category A']) !!}

And this is the result.

users list

At first glance, everything looks good, but can you spot the mistake?

Right, the third entry should be 0 and not 'Anonymous?' The nickname "0" technically is valid, right? Then what went wrong?

Global table of operators

To understand that, let's look up the second column on the negation of this table.

null comparison table

As you can see, using the ! operation, both integer 0 and string '0' values are considered equal to false, after negation, they become true, which is not what we intended to do.

If not "!", then what?

When checking strings or integers for null values, it is better to avoid loose operations and use strict === null or is_null checks are equivalent. In the same way, strictly not !== null and isset() statements are identical too.

In our specific case, we can ignore what happens with other types because the nickname argument will always be null or string; even if we pass an integer 0, it will become a string '0' because of the type hint.

function formatUser(
?User $user,
?bool $isVip,
?string $nickname,
?array $badges
): string {

We can safely use loose comparison ==, and empty string '' value will also be treated as not present, which is reasonable in this scenario.

$nickname = $nickname == null ? 'Anonymous' : $nickname;

Now, what about checking arrays or models for being empty?

Checking Non-Existing Array Keys

So why do we have empty() and isset() methods? We can not easily avoid them when working with non-existing array keys. They do not throw an Exception when accessing an undefined array key, so we can safely check for key or value presence in the array.

Non Existing Array Keys

Checking For Model Presence

Working with Eloquent is relatively straightforward. Methods like find() and first() are consistent and always return null if the record is not found. Objects are always evaluated to be true.

model presence

The same table applies when using the ->first() method.


No comments or questions yet...

Like our articles?

Become a Premium Member for $129/year or $29/month
What else you will get:
  • 59 courses (1057 lessons, total 42 h 44 min)
  • 79 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent Premium Tutorials