Operators
PHP's arithmetic and logical operators look like most other C-family languages, but its comparison operators hide the sharpest edge in the whole language: == and === do genuinely different things, and picking the wrong one is one of the most common sources of PHP bugs.
Arithmetic operators
<?php $a = 17; $b = 5; echo ($a + $b) . "\n"; echo ($a - $b) . "\n"; echo ($a * $b) . "\n"; echo ($a / $b) . "\n"; echo ($a % $b) . "\n"; echo ($a ** 2) . "\n"; ?>
22 12 85 3.4 2 289
Unlike C or Java, PHP's / always produces a real number when the division isn't even — 17 / 5 gives 3.4, not a truncated 3. % is the remainder, and ** is exponentiation ($a ** 2 means $a squared).
== versus ===
== is "loose" equality: it converts both sides to a common type before comparing, the same type-juggling behavior from the variables lesson. === is "strict" equality: it only returns true when both the value and the type already match, with no conversion:
<?php var_dump(0 == "abc"); var_dump("1" == 1); var_dump("1" === 1); var_dump(null == false); var_dump(null === false); ?>
bool(false) bool(true) bool(false) bool(true) bool(false)
"1" == 1 is true because == converts the string "1" to the integer 1 before comparing. "1" === 1 is false because a string is never identical in type to an integer, no matter what it looks like. (Note: in PHP 8+, 0 == "abc" correctly returns false — older PHP versions notoriously returned true here, one of the most infamous type-juggling surprises in the language's history.)
=== and !== everywhere. Reach for == only when you deliberately want the type conversion — comparing user-submitted form data (always strings) against a number is one of the few legitimate cases.Logical operators
<?php $age = 20; $hasId = true; var_dump($age >= 18 && $hasId); var_dump($age < 18 || $hasId); var_dump(!$hasId); ?>
bool(true) bool(true) bool(false)
&& (and), || (or), and ! (not) behave exactly as they do in JavaScript or C, including short-circuiting — in $age >= 18 && $hasId, if the first condition were false, PHP wouldn't bother evaluating $hasId at all.