---
title: "Null safe operator in practice"
url: https://www.exakat.io/null-safe-operator-in-practice/
date: 2023-12-20
modified: 2023-12-20
author: "dams"
description: "Null safe operator in practice Null-safe operator has been added to PHP 8.1: it is a new object operator that prevents a Fatal error, and its following execution stop, when..."
categories:
  - "Code auditing"
tags:
  - "null safe operator"
  - "static analysis"
image: https://www.exakat.io/wp-content/uploads/2023/12/lifesaver.320.jpg
word_count: 1146
---

# Null safe operator in practice

# Null safe operator in practice

[Null-safe operator](https://www.php.net/manual/en/language.oop5.basic.php#language.oop5.basic.nullsafe) has been added to PHP 8.1: it is a new object operator that prevents a Fatal error, and its following execution stop, when calling a method or a property on the `null` value. It has a high appeal, given that it is called 'safe' and it reduces the checks prior a method call. And the null safe operator in practice also has its own drawbacks.

The first drawback is the check that was before the method call, should actually be after it: it is still needed. The second one is that the types used in the expression must now avoid the `null` type. As usual, a new syntax just means new organisation around it. Pick your side.

Let's review that together, shall we ?

## Null safe operator

The Null safe operator `?->` is a close cousin to the object operator `->`, with whom it shares the arrow design. The difference lies in the handling of `null`, when used as the object part of the syntax.

It only works on `null` values: there is no differences when calling a method on an integer or an array: Fatal error.

The first impact of this operator is to prevent a pesky stop in execution, just because an object is not available. There are countless methods that return an object, or null in case of failure to locate the information. Those methods require an extra check on their result, and the null-safe operator is just there for this.

Hence, the name of the operator: it is safe, because it doesn't block execution if a `null` value manage to find its way. The second advantage is the short code writing: when the code is prone to errors due to `null`values, just add a question mark `?` to make the problem go away.

## Check before, check after: just check it!

When using the null-safe operator, the object being `null` cancels the whole expression: it produces a result, which is `null` itself. The story doesn't tell if it is the same `null` as the object, and that is left to the reader to figure out.

Since the execution continues, this is makes the null-safe expression optional. It might be a fire-and-forget call, where the call does something that has no local impact, like a log; it might be an optional call, or a call that fails safely. It might be a `void` returning function, but we'll come back to this case later.

On the other hand, when the expression is supposed to return a value, that value has to be checked against `null`. Remember that no check was done on the object before execution.

The first observation here is the check on null. With `->`, the ckeck is made before the call, and the returned value is only the result. With `?->`, the check is made after the call, against the returned value: the result may be any valid value, or `null` in case it was not possible.

In the end, the check was not removed, and there is still some extra code to add to ensure smooth execution.

## Which null is this?

The second observation is that the code can't differentiate between `null`because the expression has a wrong object, or `null` that is a valid returned value. Consider the `foo` method defined like this:

Traditionally, `null` is a sign of error: we asked `getInstance()` and `foo` to do something, and, at least, one of them failed. For both cases, error management might be on the menu.

More precisely, the code can't tell the source of the errors apart, because both of them are `null`. It needs an extra step to discover that source, so more code. Damned, this was just what we wanted to save.

## Typing for null-safe operator

The conclusion of that second observation is that the last method of the object expression should not return `null`. That way, a failed object expression can show its true colors, using the `null` type.

By extension, that method shall also not return `void`: while this type is different from `null`, collecting the returned value of a void-function yield... `null` again. So, this type should also be avoided.

Finally, take note that only the last called element of the object expression shall have a non-null type. In the example above, it is the `goo` method. It could be a typed property too.

All the other methods and properties in-between must succeed, and their type won't matter. In the example above, they must always return a valid type to keep the chain going. More `?->` would also be possible.

## Null safe operator in practice with static analysis

`?->` is a nice syntactic upgrade from `->`, as it makes the validation optional. For any code that is disciplined enough, it works just fine and prevents blocking bugs, while reducing the amount of code.

Yet, it should be monitored for two extra patterns:

- the [resulting value must be compared](https://exakat.readthedocs.io/en/latest/Reference/Rules/Classes/CheckAfterNullSafeOperator.html) to `null`, to allow for error management
- the [last method or property called cannot be typed nullable](https://exakat.readthedocs.io/en/latest/Reference/Rules/Classes/NoNullWithNullSafeOperator.html), to avoid confusing one error for the other.

`?->` main advantage is the switching the check's load from before the call to after the call. It comes with the possible advantage of saving the check altogether by just ignoring it.

There are many situations like this in source code : uninitialized variables, calling int-typed argument with some strings, or json_decode() without a try/catch: it works the vast majority of the time, until an error appears. And with `?->`, that error is hidden.