PHP RFC: Deprecate left-associative ternary operator
- Date: 2019-04-09
- Author: Nikita Popov nikic@php.net
- Status: Implemented
- Target Version: PHP 7.4 and PHP 8.0
- Implementation: https://github.com/php/php-src/pull/4017
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.