emty stadium seats

The Unset and the Empty

Even in impeccably designed systems, variables and array elements can behave like stealthily-planted mines. There they sit with usefully descriptive handles like $price or $business['phone'] just inviting you to trust them. So, of course, you do and bam!

OK, so that’s a warning – not particularly explosive. Still, if your system’s logic is predicated on the assumption that there is useful data in the variable or element, then Bad Things might happen. Or if, your views are particularly prone to this problem, the warnings can quickly clog up your logs – hiding more serious issues during development or even in production.

It’s not just uninitialised variables you need to watch out for, either. You might assume that a variable contains a useful value, only to find it holding false (perhaps because a function failed quietly and returned a boolean) or an empty string. This is a little less drastic than an unset variable, but any unexpected value can be problematic so, at the least, you should be ready to test for it.

TL;DR

If you’re looking for quick answer here’s a handy table with some useful approaches to the problem:

Problem Solution Code
Detect unset variable or falsy expression empty construct empty( $var )
Detect unset variable isset construct ! isset( $var )
Assign a default value if a variable is unset (all PHP) ternary operator $var = (isset($var))?$var:"default";
Assign a default value if a variable is unset (PHP 7) null coalescing operator $var = $var ?? "default";
Assign a default value if a variable is unset (PHP 7.6) null coalescing assignment operator $var ??= "default";

Want a little more than the bare bones? Read on!

Testing Expressions for emptiness

Imagine you’re working with a business array. You’re expecting a value in $business['phone'] but only want to work with the element if it has been initialised and has a truthy value.

Note A truthy variable is probably best defined as not falsy and a falsy variable is one of: undefined, false, 0, “0”, null, or an empty array.

The naive approach is to simply test like this:

This will work functionally but, if the element is not set, the code will generate a warning like the one we’ve already seen.

The answer here is to use the empty() construct.

As you might expect, empty() resolves to true if the expression you pass it resolves to a truthy value. As a bonus, if the expression is an unset variable or an array element it will count as empty without triggering a warning.

Testing that Variables are Set

Rather than check for falsiness, you may want to test that a variable has been set. You might for example, need to work with the perfectly usable values of false or 0 if assigned a initialised variable. isset() is your friend here.

isset() will resolve to false if $usernotes has not been initialised or is explicitly set to null.

Note Although empty() expects an expression, isset() expects a variable and will throw an error if you try to pass it the results of an expression.

Four Progressively Compact Ways of Setting Default Values

Already we now have enough to add a default value using a conditional statement:

In other words, if $arr['fruit0'] is not set then we assign a default string, creating the element and rendering it safe to work with.

This is a bit unwieldy, though, especially if there are many variables to test and set.

Slightly less cumbersome is the…

Ternary Operator

The ternary operator consists of three operands – a test, followed by ? and two further expressions separated by a colon (:). If the test resolves to true then ternary expression resolves to the value of the next operand, otherwise it resolves to the value of the final operand.

So this:

(true) ? "a" : "b";

will give "a". And this:

(false) ? "a" : "b";

will resolve to "b".

So we can use this operator in conjunction with isset or empty to set a default value:

Now, this is pretty ugly, but it gets the job done. There is a lot of repetition, which makes for many typo opportunities.

Luckily PHP 7 gave us the

Null Coalescing Operator

This consists of two operands: an expression to be checked and a default expression to be use if the check fails. These are separated by ??. If the test variable is set and is not null, the null coalescing expression will resolve to its value, otherwise it will resolve to the second, default, expression.

So this

$test=null;
print $test ?? "hats";

will print “hats”.

Unlike isset() the null coalescing operator does not require a variable for its test.

Here’s a quick fruity example:

This is much cleaner. Still we’re still biting into two items of fruit, here. In other words, we need to specify `$arr[‘fruit2’] once for the test expression, and again in order to reassign a value to the array element. Wouldn’t it be nice to combine the testing and the assignment so that we don’t need to repeat ourselves even this much?

PHP 7.6 made assigning default values even more compact with the:

Null Coalescing Assignment Operator

The names keep on getting longer, while the code keeps on getting shorter. The null coalescing assignment operator consists of a test variable which, if it is not set or if it resolves to null will be populated with the value of the second operand.

So, for this:

$myvar=null;
$myvar ??= "hats";

the value of $myvar will end up as "hats". But for this:

$myvar="shoes";
$myvar ??= "hats";

the value of $myvar will remain "shoes".

So now, our fruity example has become much cleaner and easier to read:

Heed the warning!

Because warning are non-fatal, it is tempting to adjust your error reporting to suppress them and carry on. But they serve a useful purpose. They ask you to think about your intentions with regard to a variable. What does it mean for this particular element to remain uninitialised? If that’s an expected scenario, then fine, remove yourself from the land of perpetual whining by giving the variable a default value. On the other hand, if your logic expects that a variable will have been initiliased at the point of access – then it’s time to find out where in your stack your assumptions have gone awry. Either way the warning will have done its job. By addressing each warning, you fix a potential logic problem or an awkward output, and by making the warning go away, you reduce noise in your logs so that you can more easily find and fix future issues.

Photo by Jean Carlo Emer on Unsplash