2

According to PHP documentation, the null coalescing operator ?? is right-associative, i.e.

$a ?? $b ?? $c

is equivalent to

$a ?? ($b ?? $c)

What is the significance of this? Does it make any difference for developers that it is left-associative or right-associative?

To those who are thinking it will call less functions, this is not true because the right operand will not be evaluated if the left operand is not null according to my test:

function f(string $a) : string {
    echo "f($a)\n";
    return $a;
}
var_dump(f("a") ?? f("b") ?? f("c") ?? f("d"));
echo "===\n";
var_dump(((f("a") ?? f("b")) ?? f("c")) ?? f("d"));

Output:

f(a)
string(1) "a"
===
f(a)
string(1) "a"
SOFe
  • 7,867
  • 4
  • 33
  • 61
  • If `$a`, `$b` and `$c` would be functions then this would lead to totally different executions if it is left or right associative as a simple example. If you use different operators additional to `??` then the same thing happens depending on the "associativeness" the code executes completely different. – Rizier123 Oct 05 '16 at 14:17
  • @Rizier123 Would it now? https://3v4l.org/PvvSr – deceze Oct 05 '16 at 14:19
  • FWIW, I cannot think of any case in which a left-associative `??` operator would produce different results in combination with stacked `??` operators. It only seems to be relevant to the internal short-circuiting; i.e. a left-associative `??` operator would always evaluate all stacked expressions (even if not their operands) instead of returning as soon as possible. You may find different behaviour combining it with other operators though. – deceze Oct 05 '16 at 14:23
  • 1
    I'd add that "Operator precedence and associativity specify grouping, but they do not specify in which order the groups are executed." https://gist.github.com/nikic/6699370 – Dmitriy Lezhnev Jul 19 '17 at 17:15

3 Answers3

0

I am thinking about performance issues, where you have to evaluate ?? multiple times (if the first value is non null) if it is left-associative while once only if it is right-associative. Compare these two cases:

(("a" ?? "b") ?? "c") ?? "d"
"a" ?? ("b" ?? ("c" ?? "d"))

On the first line, after the second (inner) parentheses ?? "b" is resolved, the value inside the first (outer) parentheses ?? "c" is resolved, then the final ?? "d" is resolved. ?? is performed 3 times.

On the second line, since "a" is not null, the whole chunk of ("b" ?? ("c" ?? "d")) does not need to be resolved. ?? is only performed once.

Although the right-hand-side value is not resolved, checking !== null fewer times might still be beneficial.

(Still, I wonder if this is the only reason?)

SOFe
  • 7,867
  • 4
  • 33
  • 61
0

As (left) operands don't have to be defined variables (containing alternatively null i.e. undefined value) and just the most right one operand within multiple (stacked) coalesce expressions without explicit parentheses grouping should be "backup value", main effect of implicit right associativity for this case seems to be that warning(s) of undefined variable(s) is (are) prevented. So, that's correct (acceptable) to use for all left operands (except for the most right) variables that aren't (or needn't to be) defined at all.

This code without explicit grouping using parentheses, so applying implicit right associativity

$a = $b ?? $c ?? $d;
echo $a;

outputs

Warning: Undefined variable $d

since all operand variables (including the most right "backup" $d) are undefined.

However, this code with explicit grouping simulating left associativity

$a = ($b ?? $c) ?? $d;
echo $a;

outputs

Warning: Undefined variable $c
Warning: Undefined variable $d

as both (all) right operands are evaluated and considered existing "backup" value.

Check here:
https://3v4l.org/ZvTl9
https://3v4l.org/pEWk9

Gordon
  • 1
  • 1
-3

What is the significance of this?

Compared to the ternary operator (which is left-associative), the null coalesce operator being right-associative allows for stacking. For example:

This won't work

echo isset($foo) ? $foo :
     isset($bar) ? $bar :
     isset($baz) ? $baz :
     'default';

This is how you might expect the ternary operator to work by default coming from C or C++, but you would be wrong. The new ?? operator allows for the following alternative:

This will work

echo $foo ?? $bar ?? $baz ?? 'default';
mister martin
  • 6,197
  • 4
  • 30
  • 63
  • 1
    And what's wrong if it is left-associative, i.e. `(($foo ?? $bar) ?? $baz) ?? 'default'`? – SOFe Oct 05 '16 at 14:16
  • @PEMapModder nothing is wrong, it's just cleaner / syntactic sugar. – mister martin Oct 05 '16 at 14:17
  • Then you aren't answering the question. "Cleaner/syntactic sugar" seems to be purely opinion-based. – SOFe Oct 05 '16 at 14:18
  • @PEMapModder you don't have to like the answer, but it is, in fact, the answer. You asked the significance, and the significance was provided. – mister martin Oct 05 '16 at 14:19
  • 1
    OP understands what `??` does and that it's easily stackable, as opposed to `?:`. The question is whether the *left* vs. *right associativity* of `??` makes any practical difference. – deceze Oct 05 '16 at 14:21
  • I asked the significance of right-associativeness of the `??` oeprator, not of the `? :` ternary operator. The left-associativeness of the `? :` operator does not concern this question at all, because it doesn't work in `? :` but works in `??`. – SOFe Oct 05 '16 at 14:25
  • "The null coalescing operator (??) has been added as **syntactic sugar** for the common case of needing to use a ternary in conjunction with isset()." - [Source](http://php.net/manual/en/migration70.new-features.php) – mister martin Oct 06 '16 at 20:12
  • @mistermartin I wasn't asking **why null coalescing operator was added**. I was asking **why it is right-associative not left-associative**. – SOFe Aug 03 '18 at 16:09
  • There is a big problem if the `?` `:` ternary operator is left-associative instead of right-associative. But for the null coalescing operator `??`, left-associative and right-associative are semantically identical. – SOFe Aug 03 '18 at 16:17