rfc:ternary_associativity

PHP RFC: Deprecate left-associative ternary operator

Introduction

Unlike most (all?) other languages, the ternary operator in PHP is left-associative rather than right-associative. The left-associative behavior is generally not useful and confusing for programmers who switch between different languages. This RFC proposes to deprecate and remove left-associativity for the ternary operator and require explicit use of parentheses instead.

As an example, the code

return $a == 1 ? 'one'
     : $a == 2 ? 'two'
     : $a == 3 ? 'three'
     : $a == 4 ? 'four'
               : 'other';

would in most (all?) other languages be interpreted as

return $a == 1 ? 'one'
     : ($a == 2 ? 'two'
     : ($a == 3 ? 'three'
     : ($a == 4 ? 'four'
               : 'other')));

which is both the useful and intuitive interpretation. In PHP, it is instead interpreted as

return ((($a == 1 ? 'one'
     : $a == 2) ? 'two'
     : $a == 3) ? 'three'
     : $a == 4) ? 'four'
               : 'other';

which is generally not what was intended.

Proposal

In PHP 7.4 using nested ternaries without explicit parentheses will throw a deprecation warning. In PHP 8.0 it will become a compile-time error instead.

1 ? 2 : 3 ? 4 : 5;   // deprecated
(1 ? 2 : 3) ? 4 : 5; // ok
1 ? 2 : (3 ? 4 : 5); // ok

This also applies when mixing short and long ternary syntax:

1 ?: 2 ? 3 : 4;   // deprecated
(1 ?: 2) ? 3 : 4; // ok
1 ?: (2 ? 3 : 4); // ok
 
1 ? 2 : 3 ?: 4;   // deprecated
(1 ? 2 : 3) ?: 4; // ok
1 ? 2 : (3 ?: 4); // ok

However, as an exception, explicit parenthesis are not required when combining two short ternaries:

1 ?: 2 ?: 3;   // ok
(1 ?: 2) ?: 3; // ok
1 ?: (2 ?: 3); // ok

The reason is that ($a ?: $b) ?: $c and $a ?: ($b ?: $c) will always yield the same result, even though the left-associative version will arrive at it in a less efficient manner.

Parentheses are also not required when nesting into the middle operand, as this is always unambiguous and not affected by associativity:

1 ? 2 ? 3 : 4 : 5 // ok
1 ? 2 ?: 3 : 4    // ok

The null-coalesce operator ?? is already right-associative and not affected by these changes.

Backward Incompatible Changes

Code exploiting left-associativity of the ternary operator will become a hard error in PHP 8. As left-associative ternaries are almost certainly bugs, the impact of this change should be minimal.

An analysis of the top 1000 composer packages found 12 instances that will be affected by this RFC. 9 of them are bugs, where a right-associative meaning was intended, but a left-associative one will be used. 3 uses of the form $a ? $b : $c ?: $d are potentially okay, because the difference between the two interpretations is small and it's not obvious to me which one is actually intended. Detailed analysis results are available at https://gist.github.com/nikic/b6214f87b0e4a7c6fe26919ac849194f.

Future Scope

We could make the ternary right-associative in a later release, after it has been an error for a while.

Vote

Voting started 2019-04-23 and ends 2019-05-07.

Deprecate and remove left-associative ternary without explicit parentheses?
Real name Yes No
andrey (andrey)  
ashnazg (ashnazg)  
bishop (bishop)  
bwoebi (bwoebi)  
carusogabriel (carusogabriel)  
derick (derick)  
didou (didou)  
diegopires (diegopires)  
duncan3dc (duncan3dc)  
emir (emir)  
galvao (galvao)  
girgias (girgias)  
guilhermeblanco (guilhermeblanco)  
jasny (jasny)  
jbnahan (jbnahan)  
jhdxr (jhdxr)  
kalle (kalle)  
kelunik (kelunik)  
kinncj (kinncj)  
levim (levim)  
malukenho (malukenho)  
marcio (marcio)  
mariano (mariano)  
mbeccati (mbeccati)  
mcmic (mcmic)  
mike (mike)  
nikic (nikic)  
ocramius (ocramius)  
patrickallaert (patrickallaert)  
petk (petk)  
pmmaga (pmmaga)  
pollita (pollita)  
rasmus (rasmus)  
reywob (reywob)  
salathe (salathe)  
santiagolizardo (santiagolizardo)  
sebastian (sebastian)  
sergey (sergey)  
stas (stas)  
trowski (trowski)  
weierophinney (weierophinney)  
yohgaki (yohgaki)  
yunosh (yunosh)  
zeev (zeev)  
zimt (zimt)  
Final result: 35 10
This poll has been closed.
rfc/ternary_associativity.txt · Last modified: 2019/05/13 15:51 by nikic