演算子の優先順位

演算子の優先順位は、二つの式が"緊密に"結合している度合いを指定します。 例えば、式 1 + 5 * 3 の答えは 16 になり、18 とはなりません。 これは乗算演算子("*")は、加算演算子("+")より高い優先順位を有するか らです。必要に応じて強制的に優先順位を設定するために括弧を使用する ことが可能です。例えば、18と評価するためには、 (1 + 5) * 3 とします。

演算子の優先順位が等しい場合は、その結合性によって評価順 (右から評価するのか、あるいは左から評価するのか) が決まります。 たとえば "-" は左結合なので、 1 - 2 - 3(1 - 2) - 3 とグループ分けされて、 評価結果は -4 になります。 一方、"=" は右結合です。つまり $a = $b = $c のグループ分けは $a = ($b = $c) となります。

優先順位が同じで結合しない演算子を並べることはできません。つまり、たとえば 1 < 2 > 1 は PHP では無効になります。 一方 1 <= 1 == 1 は問題ありません。 == 演算子の優先順位が <= 演算子より低いからです。

演算子の結合は、 二項演算子(および三項演算子) の場合にだけ意味があります。 単項演算子は、前置または後置しかないため、 演算子の結合の考え方は適用できません。 たとえば、 !!$a は、 !(!$a) という形でのみグループ化できます。

厳密には不要な場所であっても、括弧をつけておけばコードの可読性があがります。 明示的にグループ分けをしておくことで、演算子の優先順位や結合性による暗黙のグループ分けに頼らずに済むからです。

次の表では、優先順位が高い順に演算子を挙げています。 同じ行にある演算子は優先順位が等しくなります。そのような場合は、 結合時の評価にしたがってグループ分けが決まります。

演算子の優先順位
結合時の評価 演算子 追加情報
(n/a) clone new clone および new
right ** 代数演算子
(n/a) + - ++ -- ~ (int) (float) (string) (array) (object) (bool) @ 代数演算子 (単項の +-), 加算子/減算子, ビット演算子, 型の相互変換 そして エラー制御演算子
left instanceof 型演算子
(n/a) ! 論理演算子
left * / % 代数演算子
left + - . 代数演算子 (単項の +-), 配列演算子 そして 文字列演算子 (PHP 8.0.0 より前のバージョンの.)
left << >> ビット演算子
left . 文字列演算子 (PHP 8.0.0 以降)
結合しない < <= > >= 比較演算子
結合しない == != === !== <> <=> 比較演算子
left & ビット演算子 そして リファレンス
left ^ ビット演算子
left | ビット演算子
left && 論理演算子
left || 論理演算子
right ?? NULL合体演算子
結合しない ? : 三項演算子 (PHP 8.0.0 より前のバージョンでは、左結合でした)
right = += -= *= **= /= .= %= &= |= ^= <<= >>= ??= 代入演算子
(n/a) yield from yield from
(n/a) yield yield
(n/a) print print
left and 論理演算子
left xor 論理演算子
left or 論理演算子

例1 結合時の評価

<?php
$a 
5// (3 * 3) % 5 = 4
// PHP の三項演算子の結合法則は、C/C++のそれとは異なります
$a true true 2// PHP 8.0.0 より前のバージョンでは、(true ? 0 : true) ? 1 : 2 = 2

$a 1;
$b 2;
$a $b += 3// $a = ($b += 3) -> $a = 5, $b = 5
?>

演算子の優先順位や結合性は、あくまでも式のグループ分けだけを決めるものであり、評価順を決めるものではありません。 PHP では一般に、式をどの順番で評価するかは決めていません。 そのため、特定の順序で式が評価されることを前提としたコードを書いてはいけません。 PHP のバージョンが変わったり前後のコードが変わったりしたときに、評価順が変わる可能性があるからです。

例2 評価順序は未定義

<?php
$a 
1;
echo 
$a $a++; // 2 になるかもしれないし、3 になるかもしれません

$i 1;
$array[$i] = $i++; // インデックス 1 をセットするかもしれないし、インデックス 2 をセットするかもしれません
?>

例3 +-. の優先順位は同じ(PHP 8.0.0 より前のバージョン)

<?php
$x 
4;
// 次の行は、予期せぬ結果になることでしょう
echo "x minus one equals " $x-", or so I hope\n";
// なぜなら、これは次のように評価されるからです(PHP 8.0.0より前のバージョン)
echo (("x minus one equals " $x) - 1) . ", or so I hope\n";
// 期待どおりの結果を得るには、括弧を使って優先順位を指定します
echo "x minus one equals " . ($x-1) . ", or so I hope\n";
?>

上の例の出力は以下となります。

-1, or so I hope
-1, or so I hope
x minus one equals 3, or so I hope

注意:

= は他のほとんどの演算子よりも優先順位が低いはずなのにもかかわらず、 PHP は依然として if (!$a = foo()) のような式も許します。この場合は foo() の返り値が $a に代入されます。

変更履歴

バージョン 説明
8.0.0 文字列の連結 (.) の優先順位は、 代数演算子の加算/減算 (+ および -) と ビットシフト演算子 (<< および >>); よりも低くなりました。 これより前のバージョンでは、文字列の連結は +- と同じ優先順位を持ち、 <<>> よりは高い優先順位を持っていました。
8.0.0 三項演算子 (? :) は、 どの演算とも結合しなくなりました。 これより前のバージョンでは、左結合でした。
7.4.0 三項演算子(? :) が左結合であることに依存すること、 つまり、括弧で囲わずに三項演算子をネストすることは推奨されなくなりました。
7.4.0 文字列の連結 (.) 演算と、 代数演算子の加算/減算 (+ および -) と ビットシフト演算子 (<< および >>); の優先順位に依存するコードは、推奨されなくなりました。 つまり、これらを括弧を使わずに一緒に使うことは推奨されなくなりました。
add a note add a note

User Contributed Notes 8 notes

up
167
fabmlk
8 years ago
Watch out for the difference of priority between 'and vs &&' or '|| vs or':
<?php
$bool
= true && false;
var_dump($bool); // false, that's expected

$bool = true and false;
var_dump($bool); // true, ouch!
?>
Because 'and/or' have lower priority than '=' but '||/&&' have higher.
up
27
aaronw at catalyst dot net dot nz
6 years ago
If you've come here looking for a full list of PHP operators, take note that the table here is *not* complete. There are some additional operators (or operator-ish punctuation tokens) that are not included here, such as "->", "::", and "...".

For a really comprehensive list, take a look at the "List of Parser Tokens" page: http://php.net/manual/en/tokens.php
up
46
Carsten Milkau
11 years ago
Beware the unusual order of bit-wise operators and comparison operators, this has often lead to bugs in my experience. For instance:

<?php if ( $flags & MASK  == 1) do_something(); ?>

will not do what you might expect from other languages. Use

<?php if (($flags & MASK) == 1) do_something(); ?>

in PHP instead.
up
7
ivan at dilber dot info
7 years ago
<?php
// Another tricky thing here is using && or || with ternary ?:
$x && $y ? $a : $b// ($x && $y) ? $a : $b;

// while:
$x and $y ? $a : $b// $x and ($y ? $a : $b);

?>
up
4
karlisd at gmail dot com
8 years ago
Sometimes it's easier to understand things in your own examples.
If you want to play around operator precedence and look which tests will be made, you can play around with this:

<?php
function F($v) {echo $v." "; return false;}
function
T($v) {echo $v." "; return true;}

IF (
F(0) || T(1) && F(2)  || F(3)  && ! F(4) ) {
  echo
"true";
} else echo
" false";
?>
Now put in IF arguments f for false and t for true, put in them some ID's. Play out by changing "F" to "T" and vice versa, by keeping your ID the same. See output and you will know which arguments  actualy were checked.
up
-1
anisgazig at gmail dot com
3 years ago
Three types of operator associativity in php.
1.left
2.rigt
3.non-associativity

Category of three operators are right associativity
1)**
2)=,+=,-=,*=,/=,%=,&=,^=,|=,<<=,>>=,??=,.=
3)??

Category of eight operators are non-associativity
1)clone new
2)++,--,~,@
3)!
4)<,<=,>,>=
5)<<,>>
6)yield from
7)yield
8)print

Rest of the operators are left associativity
up
0
noone
4 years ago
Something that threw me of guard and I hadn't found it mentioned anywhere is if you're looking to asign a value in an if statement condition and use the same value in the said condition and compare it to a different value note the precedence of operators.

if($a=5&&$a==5){
  echo '5';
} else {
  echo 'not 5';
}
//echos  not 5

You'll get a Notice:  Undefined variable: a;
This happens because the expression is treated as
($a=5&&($a==5))
In this case $a was undefined.

Use parentheses to enforce the desired outcome or and instead of &&.
if(($a=5)&&$a==5){ // or $a=5 and $a==5
  echo '5';
} else {
  echo 'not 5';
}

//echos  5

We get no notice!

A use case for this can be a three part condition that first checks if a value is valid, second assigns a new variable based on the first value and then checks if the result is valid.

$ID=100;

if ($ID&&($data=get_table_row_for_ID($ID))&&$data->is_valid()) { //NOTE: assigned $data
// do something with the data
}

If assigning variables in an if condition I recommend adding a comment at the end of the line that such an action took place.
up
-1
instatiendaweb at gmail dot com
3 years ago
//incorrect
$a = true ? 0 : true ? 1 : 2; // (true ? 0 : true) ? 1 : 2 = 2
//Unparenthesized `a ? b : c ? d : e` is not supported. Use either `(a ? b : c) ? d : e` or `a ? b : (c ? d : e)`
//correct
$a = (true ? 0 : true) ? 1 : 2; // (true ? 0 : true) ? 1 : 2 = 2

==> correction documentation.
To Top