PHP Operators
Operators are the symbols that tell PHP what to do with your values: add two numbers, compare a password to a hash, combine strings, or decide whether a condition is true. Every non-trivial line of PHP you write leans on operators, so understanding not just what each one does but how PHP evaluates and prioritizes them is essential to avoiding subtle bugs. This lesson covers every major operator category, how PHP’s engine evaluates expressions internally, and the classic mistakes even experienced developers make.
Overview: What Operators Are and How They Work
An operator acts on one or more operands (the values or variables) to produce a result. $a + $b is an expression: $a and $b are operands, and + is the operator. PHP operators fall into distinct families, each suited to a different kind of task:
- Arithmetic — math on numbers:
+ - * / % ** - Assignment — store a value in a variable:
= += -= *= /= .= ??= - Comparison — compare two values, returning a boolean:
== === != !== < > <= >= <=> - Logical — combine boolean expressions:
&& || ! and or xor - String — concatenate text:
.and.= - Increment/Decrement — step a number by one:
++ -- - Ternary and Null Coalescing — inline conditionals:
?:and??/??= - Bitwise — operate on the binary representation of integers:
& | ^ ~ << >>
Under the hood, when the Zend engine compiles a PHP script it doesn’t just read left to right — it parses your expression into an abstract syntax tree based on each operator’s precedence (which operator binds tighter) and associativity (which direction operators of equal precedence group, left-to-right or right-to-left). That tree is then compiled into a sequence of opcodes for the Zend VM, which evaluates the innermost, highest-precedence operations first, much like solving an arithmetic expression by resolving parentheses and multiplication before addition. This is why 2 + 3 * 4 is 14, not 20 — multiplication has higher precedence than addition, so the engine builds a tree where 3 * 4 is a sub-expression evaluated before the addition.
Syntax
Operators are used directly between (or before/after) operands — there’s no special declaration syntax. The general shape is:
operand1 operator operand2
| Category | Common Operators | Example |
|---|---|---|
| Arithmetic | + - * / % ** |
$a + $b |
| Assignment | = += -= *= /= .= ??= |
$total += 10; |
| Comparison | == === != !== < > <= >= <=> |
$a === $b |
| Logical | && || ! and or |
$a && $b |
| String | . .= |
$first . $last |
| Ternary / Null coalescing | ?: ?? ??= |
$name ?? 'Guest' |
Each row above is a fully valid, standalone expression you can assign, echo, or pass as a function argument.
Examples
Example 1: Arithmetic Operators
<?php
$a = 15;
$b = 4;
echo "Sum: " . ($a + $b) . "\n";
echo "Difference: " . ($a - $b) . "\n";
echo "Product: " . ($a * $b) . "\n";
echo "Division: " . ($a / $b) . "\n";
echo "Modulus: " . ($a % $b) . "\n";
echo "Exponent: " . ($a ** 2) . "\n";
Output:
Sum: 19
Difference: 11
Product: 60
Division: 3.75
Modulus: 3
Exponent: 225
Notice that / returns a float (3.75) whenever the division isn’t exact, even though both operands are integers — PHP automatically widens the result type. % (modulus) returns the integer remainder of the division, and ** is the exponentiation operator introduced in PHP 5.6, equivalent to calling pow().
Example 2: Comparison Operators and Type Juggling
<?php
$price = "100";
$discountedPrice = 100;
var_dump($price == $discountedPrice);
var_dump($price === $discountedPrice);
echo (10 <=> 10) . "\n";
echo (5 <=> 10) . "\n";
echo (10 <=> 5) . "\n";
Output:
bool(true)
bool(false)
0
-1
1
The loose equality operator == converts types before comparing, so the string "100" and the integer 100 are considered equal. The strict operator === requires both value and type to match, so it returns false. The last three lines use the spaceship operator (<=>), which returns 0 if the operands are equal, a negative number if the left is smaller, and a positive number if the left is larger — it’s the building block behind custom sort callbacks like usort().
Example 3: Logical, Ternary, Null Coalescing, and Compound Assignment
<?php
function calculateTotal(float $subtotal, ?float $discountPercent = null): string
{
$discountPercent ??= 0.0;
$isEligible = $subtotal >= 50 && $discountPercent > 0;
$finalTotal = $isEligible
? $subtotal - ($subtotal * $discountPercent / 100)
: $subtotal;
return number_format($finalTotal, 2);
}
echo calculateTotal(80.0, 10) . "\n";
echo calculateTotal(30.0, 10) . "\n";
echo calculateTotal(120.0) . "\n";
$total = 0;
$total += 25;
$total *= 2;
echo $total . "\n";
Output:
72.00
30.00
120.00
50
The null coalescing assignment ??= only assigns a value if the variable is currently null, which is exactly what we want for an optional parameter. The logical && combines two boolean checks (minimum subtotal and a positive discount) into one eligibility flag, and the ternary ?: picks between the discounted and full price without a multi-line if. Finally, the compound assignment operators += and *= update $total in place, saving you from writing $total = $total + 25;.
How PHP Evaluates Expressions Step by Step (Under the Hood)
When PHP compiles a line like $result = 2 + 3 * 4;, it does not evaluate left to right. Instead, it consults its internal operator precedence table (documented in the PHP manual) to decide which operations bind first, then builds an expression tree accordingly:
<?php
$result = 2 + 3 * 4;
echo $result . "\n";
$result2 = (2 + 3) * 4;
echo $result2 . "\n";
Output:
14
20
In the first line, * has higher precedence than +, so the engine evaluates 3 * 4 first, producing 12, then adds 2 to get 14. Wrapping 2 + 3 in parentheses forces that sub-expression to be evaluated first regardless of precedence, changing the result to 20. This same mechanism governs every expression in your code — comparisons, logical combinations, string concatenation — which is why parentheses are the simplest way to make evaluation order explicit and self-documenting, rather than relying on readers to memorize the precedence table.
Common Mistakes
Mistake 1: Confusing Assignment (=) with Comparison (==)
This is the single most common PHP typo, and it’s dangerous precisely because it doesn’t cause an error — if ($age = 18) is valid PHP that assigns 18 to $age and then evaluates the assignment’s result (which is truthy) as the condition.
<?php
$age = 15;
if ($age = 18) {
echo "You are an adult.\n";
} else {
echo "You are a minor.\n";
}
Because $age gets overwritten with 18 and the assignment expression evaluates to a truthy value, this always prints "You are an adult." — regardless of the original age. The fix is to use the comparison operator:
<?php
$age = 15;
if ($age == 18) {
echo "You are an adult.\n";
} else {
echo "You are a minor.\n";
}
Output:
You are a minor.
Mistake 2: Mixing and/or with Assignment
PHP has two sets of logical operators — &&/|| and and/or — and they are not interchangeable despite looking equivalent, because and and or have much lower precedence than =.
<?php
$isAdmin = false or true;
var_dump($isAdmin);
You might expect $isAdmin to become true, but because = binds tighter than or, this is actually parsed as ($isAdmin = false) or true; — the assignment happens first with false, and the or true is discarded.
Output: bool(false)
Using the higher-precedence || operator instead fixes the trap:
<?php
$isAdmin = false || true;
var_dump($isAdmin);
Output:
bool(true)
Best Practices
- Default to
===and!==over==and!=to avoid unexpected type-juggling bugs, especially when comparing user input or database results. - Prefer
&&/||overand/orin conditional logic; reserveand/orfor rare cases like error-flow control where their low precedence is intentional. - Use parentheses liberally in mixed expressions — they cost nothing at runtime and make evaluation order obvious to future readers (including you).
- Reach for
??and??=instead ofisset()ternaries when handling optional values or default settings. - Use compound assignment operators (
+=,.=, etc.) for accumulator patterns — they’re clearer and slightly more efficient than repeating the variable name. - Never assign inside a condition unless it is a deliberate, well-commented idiom (like
while ($row = $stmt->fetch())) — accidental assignment is the source of many silent bugs.
Practice Exercises
- Exercise 1: Write a script with two integer variables,
$x = 17and$y = 5. Print the result of every arithmetic operator (+ - * / % **) applied to them, each on its own line with a label. - Exercise 2: Given
$stock = 0, write an expression using the null coalescing operator and the ternary operator together to print"Out of stock"when$stockis falsy/zero, or"In stock: N"otherwise. - Exercise 3: Predict, then verify by reasoning through precedence rules, what
$result = 10 - 2 * 3 > 0 && 5;assigns to$result, and explain which operator resolves first and why.
Summary
- Operators act on operands to produce a result, and PHP groups them into arithmetic, assignment, comparison, logical, string, ternary/null-coalescing, and bitwise families.
- Precedence and associativity — not left-to-right reading order — determine how PHP’s engine actually evaluates a compound expression.
==compares after type conversion;===requires matching type and value — prefer the strict form to avoid surprises.&&/||have much higher precedence thanand/or, which can silently change behavior when mixed with assignment.- Modern operators like
??,??=, and<=>let you express defaults and comparisons more concisely and safely than older idioms. - When in doubt about evaluation order, use parentheses — they make intent explicit and prevent precedence-related bugs.
