Null Safe Operators

October 8, 2023

I've always been extremely pedantic about checking that things exist before trying to use them. Recently, thanks in part to some new features available in PHP 8+, I've learned that it's possible to write much more concise code that's equally robust.

For the past couple of years I've been using the null coalescing and null coalescing assignment operators that have been available since PHP 7.4, which saves a lot of having to to this sort of thing:

if (!isset($foo)) {
	$foo = [];
if (!isset($foo['bar'])) {
	$foo['bar'] = 1;

This can all be replaced with just $foo['bar'] ??= 1.

More recently, I've learned two additional things that help me write a lot fewer lines:

  1. PHP 8 introduced an additional null safe operator that allows properties or methods to be chained on null objects to similar effect, allowing for something like $node?->get('field_foo')?->first()?->get('entity) without having to worry about generating an exception if, say, field_foo is empty.
  2. It's not necessary to explicitly test for every level of a multidimensional array, e.g., isset($foo[‘bar’][0]) won’t generate a warning if $foo[‘bar’] doesn’t exist. (Turns out I wasted a lot of time writing consecutive isset() tests to drill down into Drupal's many multidimensional arrays, especially back in the pre-Drupal 8 days when comically deep arrays were everywhere.)

One Drupal-specific caveat I discovered to point 1: $node?->get(‘field_foo’) will still generate an exception if field_foo doesn’t exist, so $node->hasField(‘field_foo’) still has to be tested before $node?->get('field_foo') can be used safely.

Photo of the Charles River in Boston at night

North Point Park and the Charles River in Boston/Cambridge, Massachusetts, August 2023.