Does null conditional operator always break on first null ocurrence?

90 Views Asked by At

Having a C# background, I always use the ?. operator when acessing class properties (when using Entity Framework relationships).

For example, if I use this and the status class is null, it'll throw an exception since I'm trying to get a property out of a null object.

var order = DB.Order.Find(1);

var status = order.status.text;

To fix this, I could do something like this:

var address = order.status?.text ?? "No status";

The ?. operator will break on the first null and skip the rest of the acessings.

I came across the same situation in PHP and had to do something like this:

$order = Orders::find(1);
$status = $order->status->text;

If the status is empty, it'll throw the same exception (trying to get property out of a null object).

But then I did this and it worked:

$status = $order->status->text ?? "No status";

Apparently, PHP is skipping the ->text acessing if status is null.

I created a fiddle to check if this is not only in my environment, and surprisingly it worked just fine!

<?php
$j = "Hello!";
echo $a->b->c->d->e ?? $a->b->c->d ?? $a->b->c ?? $a->b ?? $j;

<< "Hello!"

Is this really the expected behavior of the ?? operator in PHP? Because I didnd't see this mentioned in the docs.

1

There are 1 best solutions below

1
On BEST ANSWER

After some research, I found out that the null-conditional operator (??) that was added in PHP 7 is basically a syntatic sugar for the isset() function as if it were used in a ternary call.

echo isset($a->b->c) ? $a->b->c : "Hello!";

The documentation for the isset function shows a clear example of an attempt to access deep array values:

<?php

$a = array ('test' => 1, 'hello' => NULL, 'pie' => array('a' => 'apple'));

// Checking deeper array values
var_dump(isset($a['pie']['a']));        // TRUE
var_dump(isset($a['pie']['b']));        // FALSE
var_dump(isset($a['cake']['a']['b']));  // FALSE

?>

The isset() function doesn't throw an E_NOTICE when the variable is null, it just skips the rest of the acessing. Since the null coalesce operator basically uses isset() internally, it also won't throw an exception when trying to access a property on a null object.

Here is the link to the implementation suggestion, it contains a link to the merge request containing the source code of this operator.