【PHP8.0】演算子.と+の優先順位が変わる


PHP7.3現在、演算子+-.の優先順位は同じです。

すなわち左から右に評価されます。

    echo 1 . 2 + 3 . 4;

    echo ((( 1 . 2 ) + 3 ) . 4 ) ; // これと同じ

マニュアルでもわざわざ例を挙げて解説しています。

さて2019年3月にChange the precedence of the concatenation operatorというRFCが提出されました
2019/05/07現在は投票中のステータスですが賛成多数で、PHP8で上記の動作は変わることになりそうです。
演算子の追加削除はよくあることですが、優先順位の変更というのは他言語含めてもなかなか見ることのないレアなイベントではないでしょうか。

Change the precedence of the concatenation operator

Introduction

+-、そして.は長年にわたる問題です。
それは左から右に解釈されます。

echo "sum: " . $a + $b;

// こう解釈される
echo ("sum: " . $a) + $b;

// こうではない
echo "sum :" . ($a + $b);

このRFCでは、この動作をより直感的に、問題が出にくくなるようにすることを目的としています。

Proposal

現在、+-.の各演算子は優先順位が同じです。
これらは、単純に左から右に評価されます。

これは直感に反します。
一般に、数字ではない文字列を足したり引いたりすることはほとんどありません。
PHPが整数を文字列にシームレスに変換できることを考えると、文字列連結が先に来ることが望ましいでしょう。

従って、このRFCでは.に、+-より低い優先順位を与えることを提案します。
具体的には、新しい優先順位は<<>>のすぐ下になります。

Backward Incompatible Changes

.の後に、括弧を使わず+-を使用している式全てが影響を受けます。
例として、"3" . "5" + 742ではなく"312"になります。

これは、予告や警告なしに出力が変更されるという点で微妙な動作変更ですが、コードを静的解析して、この問題が発生する箇所を全て見つけることは簡単にできます。
私の知るかぎり、この問題が発生することは稀であり、そして大抵は最初から間違っています。

NikitaがMLで言及したように、既存のOSSへの影響は事実上ありません。
見つかったものは全て単なるバグです。
つまり、全体的に影響は非常に小さいということになります。

Proposed PHP Version

PHP7.4でE_DEPRECATEDを発生させ、PHP8で動作を変更します。

投票

投票開始は2019/04/30、投票終了は2019/05/14です。
2019/05/07現在、PHP8で動作変更する提案は賛成23反対3で、ほぼ確実に受理されます。
PHP7.4でDeprecatedにする提案は賛成23反対4で、こちらもおそらく受理されます。

NikitaのML

またNikitaか。

Composerパッケージの上位2000件を調査したところ、影響を受けるコードは僅か5件しかありませんでした
しかも5件とも修正後の優先順位を想定したコードで、つまり現状ではバグっています。

$this->errors->add( 'unknown_upgrade_error_' . $errors_count + 1, $string );

例を一つあげると、上記コードはadd('unknown_upgrade_error_5', $string)のような文字列を与えたいのだと思われますが、実際はadd(1, $string)になります。

今回のRFCが通ると、想定していたであろう動作にエンバグすることになります。

感想

考えてみたら、むしろどうして今まで同じだったんだ、って感じですね。
優先順位が同じであるという仕様と、文字列と数値を自由に行き来できるという仕様が相まって、PHPで.+を同時に使った演算は、ぱっと見から予想できない結果になることがありました。
今回のRFCが通ると、そのあたりの動作がすっきりすることになります。

もっとも、そういったややこしい演算には普通は括弧を使っているから、実害は全くないはずですけどね。

ところでDeprecateにする提案に"The second (secondary) voting requires a 50%+1 majority."って書いてあるんだけど、50%の投票は廃棄されたんじゃなかったのか?