Deprecate left-associative ternary operatorというRFCが投票に入っています。
提案者のNikitaは、最近アロー関数やらAlways generate fatal error for incompatible method signaturesやらConsistent type errors for internal functionsやら立て続けに凄い勢いで活躍しててすごい草生えてる。
過去一年のcontributions2000超えって何なの…?
Deprecate left-associative ternary operator
Introduction
ほとんど(全て?)の他言語と異なり、PHPの三項演算子は右結合ではなく左結合です。
左結合の振る舞いは一般的に有用ではなく、複数言語を使い分けるプログラマにとって混乱の元になっています。
このRFCでは三項演算子の左結合性を廃止・削除し、かわりに括弧の明示的な使用を強制します。
例として以下のコードを上げます。
return $a == 1 ? 'one'
: $a == 2 ? 'two'
: $a == 3 ? 'three'
: $a == 4 ? 'four'
: 'other';
大抵の言語ではこのように解釈されます。
return $a == 1 ? 'one'
: ($a == 2 ? 'two'
: ($a == 3 ? 'three'
: ($a == 4 ? 'four'
: 'other')));
これは直感的であり便利な解釈です。
PHPではそうではなく次のようになります。
return ((($a == 1 ? 'one'
: $a == 2) ? 'two'
: $a == 3) ? 'three'
: $a == 4) ? 'four'
: 'other';
これは一般的に考えられるような動作ではありません。
Proposal
PHP7.4では、括弧を使わずに三項演算子のネストを使用すると非推奨の警告を表示します。
PHP8では、コンパイルエラーになります。
1 ? 2 : 3 ? 4 : 5; // deprecated
(1 ? 2 : 3) ? 4 : 5; // ok
1 ? 2 : (3 ? 4 : 5); // ok
これはエルビス演算子においても同様です。
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
ただし例外として、エルビス演算子を2回重ねる場合は括弧が必要ありません。
1 ?: 2 ?: 3; // ok
(1 ?: 2) ?: 3; // ok
1 ?: (2 ?: 3); // ok
なぜかというと、($a ?: $b) ?: $c
と$a ?: ($b ?: $c)
は左結合であろうと右結合であろうと常に同じ結果になるからです。
三項演算子の中央を三項演算子にする場合も括弧は必要ありません。
これは解釈を間違えることがなく、結合性の影響を受けないからです。
1 ? 2 ? 3 : 4 : 5 // ok
1 ? 2 ?: 3 : 4 // ok
Null合体演算子??
は既に右結合なので、このRFCによる影響はありません。
Backward Incompatible Changes
三項演算子の左結合性を悪用するコードは、PHP8ではエラーになります。
左結合の三項演算子を使っているようなコードはほぼ確実にバグなので、このRFCによる影響は最小限に抑えられます。
Future Scope
しばらくエラーにしておけば、いずれ正しい三項演算子にすることができます。
投票
2019/04/23に投票開始、2019/05/07に投票終了。
有権者の2/3+1の賛成で受理されます。
2019/04/25時点では賛成22、反対8で、賛成が優勢ですが、まだ簡単にひっくり返る程度の差です。
果たしてどうなることでしょうか。
感想
一気に他言語と同じ動作にしてしまうと、同じ書き方でもPHPのバージョンによって動作が完全に異なってしまい、間違いなく大混乱になるでしょう。
そのためいったん動かないようにして、順次移行するという形にしたようです。
前三項演算子について調べたとき、PHPと同じ解釈をする言語がひとつだけあったと思うんだけど何だったっけ。
その言語にとっては遂に仲間が居なくなってしまいますね。
まあそもそも根本的に、三項演算子をネストするなって話ですが。
遊ぶと楽しいのは確かですが、会社でこんなコードを書いてきたらぶん殴られて当然です。