突然ですがPHP駆け出しエンジニアのみなさま!
タイトルの問題、正しく計算できるでしょうか?
私は初見は引っかかってしまいました。
答えは「2」です。
正しく計算できた方、なぜそうなるかきちんと説明できますか?
この記事を読んで、明日からは「演算子」について自信をもってコードを書けるようになりましょう!
1 演算子
1.1 演算子とは
演算子とは「値に対して行ってなにがしか別の値を生み出すような操作」のことです。
簡単に言えば、値を変化させるような操作すべてを表します。
PHPでは単項、二項、三項演算子が扱われ、タイトルの問題は三項演算子が「ネスト(入れ子)」になっているものです。
1.2 演算子の種類と優先順位
ここでは演算子の詳細な解説は省きます。知らないものがあった場合はグーグル先生に聞いてください。
演算子には、種類によって結合法則と優先順位が異なります。
それぞれの語句の意味を説明したうえで、結合法則と優先順位をまとめたマトリクスを提示します。
1.2.1 結合法則
結合法則とは、2つの値を演算子を用いて演算する際に、右辺と左辺どちらから評価されるのかを決める法則である。
結合法則には左結合と右結合と、結合しないものとに分類される。
特に、PHPの場合、他の言語と異なり三項演算が左結合となることに留意が必要である。
PHPでは多数派は左結合となるので、右結合と結合しない例のみを列挙しておく。
1.2.1.1 右結合の演算子の一覧
- (int)など、@ キャスト、エラー制御演算子
- ! 論理演算子
- =, +=, -=, *=, /=, .=, %=, &=, |=, ^=, <<=, >>=, => 代入演算子
1.2.1.2 結合なしの演算子の一覧
- new, clone オブジェクトの生成、複製
- ++, -- 加算子、減算子
- instanceof 型
- <, <=, >, >=, <> 比較演算子
- ==, !=, ===, !== 比較演算子
1.2.2 優先順位
演算子の優先順位とは、複数の演算子が連続した場合に、どの演算子から先に評価していくかを定めたルールである。
例えばイメージしやすいものであれば、同じ代数演算子でも*と/は+や-よりも優先順位が高い。
いくつもの演算子が用いられる場合や、ネストで式を記述する際には、わかりやすくするために()を明示的に用いて優先順位を示すのも良い。
例えば
2 * 3 + 5
であれば
((2 * 3) + 5)
のような意味です。
1.3 演算子の結合法則と優先順位の表
上から順に優先順位が高く評価される演算子となります。
結合法則 | 演算子 | 説明 |
---|---|---|
結合しない | new, clone | オブジェクトの生成、複製 |
右結合 | [ | 配列のブラケット |
結合しない | ++, -- | 加算子、減算子 |
右結合 | ~, -, (int)など, @ | キャスト、エラー制御演算子 |
結合しない | instanceof | 型 |
右結合 | ! | 論理演算子 |
左結合 | *, /, % | 代数演算子 |
左結合 | +, -, . | 代数演算子、文字列演算子 |
左結合 | <<, >> | ビット演算子 |
結合しない | <, <=, >, >=, <> | 比較演算子 |
結合しない | ==, !==, ===, !== | 比較演算子 |
左結合 | & | ビット演算子、 参照 |
左結合 | ^ | ビット演算子 |
左結合 | ||
左結合 | && | ビット演識 |
左結合 | || | 論理演算子 |
左結合 | ?, : | 三項演算子 |
右結合 | =, +=, -=, *=, /=, .=, %=, &=, |=, ^=, <<=, >>=, | 代入演算子 |
左結合 | and | 論理演算子 |
左結合 | xor | 論理演算子 |
左結合 | or | 論理演算子 |
左結合 | . |
こう見ると、同じ種類の演算子の間でも優先順位がつけられていることわかりますね。
2 タイトルの問題の解説
タイトルの問題を再掲します。
echo true ? 1 : false ? 2 : 0;
起きがちな間違いは、単純に左から進めて言って「1」と答えることです。
この問題は、結合法則のみで解くことができます。
結合法則の評に基づき評価される順に()を付けて書き直すと
echo ②( ①( true ? 1 : false? ) ? 2 : 0);
となります。
まず、三項演算は左結合のため、演算子?、:の左から評価します。
最初①部の処理です。
?の左にあるtrueが評価され、真です。
次に真の場合は:の左側である1を評価し、1となります。
ここまで評価した段階で①括弧内が整理され、この式は
echo ②( ①(1) ? 2 : 0);
と表すことができると思います。
すると、②の挙動とは、
「三項演算子「?」の前にある①(1)を評価し、真ならば2を、偽ならば0」を表示することとなります。
本問では、(1)は真なので、答えは2となります
このように括弧を表示するとネスト構造の演算子はみやすくなります。
思わぬエラーを引き起こさないように気をつけていきましょう!