Operator Precedence and Associativity
Which operator binds first, why ** is right-associative, and how a stray precedence assumption becomes a real bug.
Precedence decides who grabs the operands first; associativity breaks ties among equal operators. You don't need to memorise the whole table — you need to know the handful that bite.
The ones that catch people
**is right-associative and higher than unary minus:-3 ** 2is-9.&&binds tighter than||:a || b && cmeansa || (b && c).- The word forms
and/orbind looser than=— a classic assignment surprise. - Concatenation
.now binds looser than+/-(changed in PHP 8), so"sum: " . 1 + 2parses as"sum: " . (1 + 2).
Easy example
<?php
var_dump(2 + 3 * 4); // 14, not 20
var_dump(2 ** 3 ** 2); // 512, right-associative
var_dump(true || false && false); // trueExample
Loading editor…
Press Run to execute the code.
When to use it
- Parenthesise a bitwise OR expression inside an if condition to prevent it being mistaken for logical OR.
- Use explicit parentheses around arithmetic in a complex discount formula to document intended calculation order.
- Rely on knowing ** is right-associative to write clean repeated-power expressions without extra variables.
More examples
Precedence changes the result
* has higher precedence than +; ** is right-associative — parentheses make the intended order explicit and safe.
<?php
$a = 2 + 3 * 4; // 14: * before +
$b = (2 + 3) * 4; // 20: parentheses first
$c = 2 ** 3 ** 2; // 512: right-assoc: 2**(3**2)=2**9
$d = (2 ** 3) ** 2; // 64: left first
echo "$a $b $c $d";Boolean vs bitwise confusion
Mixing | (bitwise OR) with || (logical OR) is a common precedence confusion; use parentheses and the right operator.
<?php
$perm = 6; // binary 110
$read = 1; // 001
$write = 2; // 010
// Bug: || returns true/false, not the bit result
if ($perm || $write) { echo 'wrong'; }
// Correct: use & for bitwise AND check
if ($perm & $write) { echo 'has write'; }Complex expression with parens
Explicit parentheses communicate the intended order and prevent subtle precedence bugs in multi-step formulas.
<?php
$price = 100;
$discount = 0.1;
$tax = 0.08;
// Without parens: wrong order
$bad = $price - $price * $discount + $tax * $price;
// With parens: clear intent
$good = ($price * (1 - $discount)) * (1 + $tax);
echo round($bad, 2); // 98.0 (wrong)
echo round($good, 2); // 97.2 (correct)
Discussion