28

I would like to omit checks for null in chained statements like

if($a && $a->$b && $a->$b->$c){
  $d = $a->$b->$c;
}

and use optional chaining instead.

Is this possible or implemented in PHP?

Chris Jung
  • 974
  • 2
  • 8
  • 17

4 Answers4

35

Not until PHP 8.0.

This has been voted on and passed in the Nullsafe operator RFC.

The syntax will be ?->.

So the statement:

if ($a && $a->$b && $a->$b->$c) {
  $d = $a->$b->$c;
}

Could be rewritten to:

$d = $a?->$b?->$c;  // If you are happy to assign null to $d upon failure

Or:

if ($a?->$b?->$c) {
  $d = $a->$b->$c; // If you want to keep it exactly per the previous statement
}

The Nullsafe operator works for both properties and methods.

Paul
  • 6,572
  • 2
  • 39
  • 51
  • 5
    Coming from Swift, I instantly typed ?-> thinking it would work, but before giving it a try I looked this up and ended here! – om-ha Feb 28 '21 at 23:37
33

According to this article "The null coalescing operator ( introduced in PHP 7) is represented like this ?? used to check if the value is set or null, or in other words, if the value exists and not null, then it returns the first operand, otherwise, it returns the second operand."

So you can easily do

$d = $a->$b->$c ?? 'DEFAULT' ; 

EDIT: This only works for properties, not methods (as pointed out by "hackel" in the comments below)

James
  • 4,644
  • 5
  • 37
  • 48
Foued MOUSSI
  • 4,643
  • 3
  • 19
  • 39
  • 1
    Didn't know this also works for chaining. Best solution. – Michael Jan 23 '20 at 14:58
  • 1
    did you verified this information yourself? it seems that it doesn't work at all `class Something { public function getSomething() { return null; } } $something = new Something(); var_dump($something->getSomething()->getSomethingElse() ?? 'default'); ` produces `Fatal error: Uncaught Error: Call to a member function getSomethingElse() on null` – Oliboy50 Apr 23 '20 at 08:32
  • 2
    According to the docs, the null coalescing operator is just syntantic sugar: `exprA ?? exprB` is equivalent to `isset(exprA) ? exprA : exprB`. isset supports something like optional chaining but just for arrays. `$empty = []; isset($empty['a']['b']); // false, no exception` – Kevin Peña May 04 '20 at 15:28
  • 2
    @Oliboy50 It only works for properties, not methods. e.g. `$a = new class () { public $b; }; $d = $a->b->c ?? 'DEFAULT';` – hackel May 29 '20 at 01:04
  • 1
    Thank you @hackel I edited and removed my downvote then :) – Oliboy50 May 30 '20 at 09:48
13

In PHP versions less than 8, optional chaining isn't supported. You can emulate it for properties by using the error control operator (@) which will suppress any errors that would normally occur from the assignment. For example:

$b = 'b';
$c = 'c';
$e = 'e';
$a = (object)['b' => (object)['e' => 2]];
@$d = $a->$b->$c;
var_dump($d);
@$d = $a->$b->$e;
var_dump($d);

Output:

NULL
int(2)

Demo on 3v4l.org

A better solution is to use the null coalescing operator as described in @FouedMOUSSI answer.

As of PHP8 (released 2020-11-26) optional chaining is supported via the nullsafe operator (see @Paul answer or the posted duplicate).

Nick
  • 138,499
  • 22
  • 57
  • 95
3

As mentioned by @Paul the nullsafe is available in PHP 8. After reading this question today I just realized PHP 8 was released yesterday (2020-11-26) with nullsafe operators available :)

So yes it is available in PHP now and I can't wait to use it.

https://www.php.net/releases/8.0/en.php

penance
  • 91
  • 6