Lesson 3 • Beginner
Operators & Expressions ➕
By the end of this lesson you'll be able to do maths, join text, and compare values in PHP — and you'll know the one comparison rule (=== over ==) that prevents a whole category of bugs.
What You'll Learn in This Lesson
- Do arithmetic with + - * / % and ** (exponentiation)
- Join text with the . operator and append with .=
- Use assignment shortcuts (+= -= ++ --) to update variables
- Tell == (loose) from === (strict) and know which to reach for
- Compare with <=> (spaceship) and combine conditions with && || !
- Provide fallbacks with ?? and ??=, and write one-line ternary choices
$variables and printing them with echo before you start.php file.php. The Output panel under each example shows exactly what to expect.1️⃣ Arithmetic Operators
An operator is a symbol that acts on values — the values it works on are called its operands. The arithmetic ones do exactly what you'd expect from a calculator: +, -, *, and /. Two are worth a closer look: % (modulus) gives the remainder after dividing — great for "is this number even?" — and ** raises a number to a power. Note that / can return a float (a decimal) even when both inputs are whole numbers.
<?php
// An OPERATOR is a symbol that does something to values (the "operands").
// $a + $b -> + is the operator, $a and $b are the operands.
$a = 15;
$b = 4;
// The six arithmetic operators. Each line builds a string with the . operator
// (more on . in a moment) and echoes the result.
echo "15 + 4 = " . ($a + $b) . "\n"; // 19 addition
echo "15 - 4 = " . ($a - $b) . "\n"; // 11 subtraction
echo "15 * 4 = " . ($a * $b) . "\n"; // 60 multiplication
echo "15 / 4 = " . ($a / $b) . "\n"; // 3.75 division ALWAYS returns a float here
echo "15 % 4 = " . ($a % $b) . "\n"; // 3 modulus = the REMAINDER after dividing
echo "15 ** 4 = " . ($a ** $b) . "\n"; // 50625 exponentiation: 15 to the power of 4
?>15 + 4 = 19
15 - 4 = 11
15 * 4 = 60
15 / 4 = 3.75
15 % 4 = 3
15 ** 4 = 506252️⃣ Joining Text: . and .=
This is the one that trips up newcomers from other languages: PHP joins strings with the dot (.), not the plus sign. Writing "5" + "3" tries to add them as numbers (giving 8), whereas "5" . "3" glues them into "53". The .= operator is the text version of += — it appends to a string you already have.
<?php
// PHP joins strings with the DOT ( . ), NOT the + sign.
// (Using + on two strings tries to ADD them as numbers — a classic trap.)
$first = "Ada";
$last = "Lovelace";
// '.' glues pieces together. Note the literal space " " in the middle.
$fullName = $first . " " . $last;
echo $fullName . "\n"; // Ada Lovelace
// '.=' APPENDS to a string in place — like += but for text.
$greeting = "Hello";
$greeting .= ", " . $first; // adds ", Ada" onto the end
$greeting .= "!"; // adds "!" onto the end
echo $greeting . "\n"; // Hello, Ada!
// Inside "double quotes" PHP also expands variables directly — handy too.
echo "Welcome back, $first.\n"; // Welcome back, Ada.
?>Ada Lovelace
Hello, Ada!
Welcome back, Ada.3️⃣ Assignment & Increment
A single = is assignment — it stores the value on the right into the variable on the left (it is not "equals"; that's ==, coming next). The compound operators (+= -= *= /= %=) do a calculation and reassign in one step, so $x += 5 just means $x = $x + 5. To bump a value by exactly 1, use ++ or -- — and watch the position: $n++ uses the value then adds, while ++$n adds then uses.
<?php
// '=' is ASSIGNMENT: it puts the value on the right into the variable on the left.
// The compound operators below do a calculation AND reassign in one step.
$x = 10; echo "start: \$x = $x\n"; // start: $x = 10
$x += 5; echo "+= 5: \$x = $x\n"; // 15 same as $x = $x + 5
$x -= 3; echo "-= 3: \$x = $x\n"; // 12 same as $x = $x - 3
$x *= 2; echo "*= 2: \$x = $x\n"; // 24 same as $x = $x * 2
$x /= 4; echo "/= 4: \$x = $x\n"; // 6 same as $x = $x / 4
$x %= 4; echo "%= 4: \$x = $x\n"; // 2 same as $x = $x % 4
// ++ and -- add or subtract exactly 1. POSITION matters:
$n = 5;
echo "\$n++ gives " . ($n++) . ", then \$n is $n\n"; // gives 5, then 6 (use-then-add)
echo "++\$n gives " . (++$n) . ", then \$n is $n\n"; // gives 7, then 7 (add-then-use)
?>start: $x = 10
+= 5: $x = 15
-= 3: $x = 12
*= 2: $x = 24
/= 4: $x = 6
%= 4: $x = 2
$n++ gives 5, then $n is 6
++$n gives 7, then $n is 74️⃣ Comparison: == vs === and the Spaceship
Comparison operators ask a yes/no question and hand back a boolean (true or false). The most important rule in this whole lesson lives here. == is loose equality: it converts types first, so 5 == "5" is true. === is strict equality: the value and the type must match, so 5 === "5" is false. Prefer === almost always — loose comparison ("type juggling") is a famous source of bugs. The other operators are != (not equal), <, >, <=, >=, and the spaceship <=>, which returns -1, 0, or 1 for a three-way compare (ideal for sorting).
<?php
// COMPARISON operators ask a yes/no question and return a bool (true / false).
// var_export() prints true/false literally so you can SEE the answer.
// == is LOOSE equality: it converts types first, so surprises happen.
// === is STRICT equality: values AND types must match. Prefer === almost always.
echo "5 == '5' -> "; var_export(5 == "5"); echo "\n"; // true (string "5" becomes 5)
echo "5 === '5' -> "; var_export(5 === "5"); echo "\n"; // false (int vs string)
echo "0 == 'a' -> "; var_export(0 == "a"); echo "\n"; // false (modern PHP 8+)
echo "1 != 2 -> "; var_export(1 != 2); echo "\n"; // true (not equal)
echo "3 <= 3 -> "; var_export(3 <= 3); echo "\n"; // true (less than OR equal)
// The SPACESHIP <=> returns -1, 0, or 1 for a three-way compare.
// Perfect for sorting: it tells you "smaller", "equal", or "larger".
echo "1 <=> 5 -> " . (1 <=> 5) . "\n"; // -1 left is smaller
echo "5 <=> 5 -> " . (5 <=> 5) . "\n"; // 0 they are equal
echo "9 <=> 5 -> " . (9 <=> 5) . "\n"; // 1 left is larger
?>5 == '5' -> true
5 === '5' -> false
0 == 'a' -> false
1 != 2 -> true
3 <= 3 -> true
1 <=> 5 -> -1
5 <=> 5 -> 0
9 <=> 5 -> 1Now you try. The script below is almost complete — fill in each ___ using the 👉 hint, then run it and check it against the Output panel.
<?php
// 🎯 YOUR TURN — fill in each blank marked ___ , then run it.
// Goal: build a full sentence using arithmetic AND string concatenation.
$price = 8;
$qty = 3;
// 1) Work out the total cost (price times quantity)
$total = $price ___ $qty; // 👉 replace ___ with the multiply operator ( * )
// 2) Join the pieces into one string with the DOT operator
echo "Total: " ___ $total ___ " dollars\n"; // 👉 replace each ___ with a dot ( . )
// ✅ Expected output:
// Total: 24 dollars
?>Total: 24 dollars___ with * and the others with the dot . operator, then run it. You should get Total: 24 dollars.5️⃣ Logical Operators
Logical operators combine true/false values so you can ask compound questions. && (AND) is true only when both sides are true; || (OR) is true when either side is true; ! (NOT) flips a boolean. PHP also has word forms and / or — they look friendlier but bind looser than =, which causes a classic surprise shown below. The advice is simple: use && and ||.
<?php
// LOGICAL operators combine true/false values into a single yes/no answer.
// && AND -> true only if BOTH sides are true
// || OR -> true if EITHER side is true
// ! NOT -> flips true to false and back
$loggedIn = true;
$isAdmin = false;
var_export($loggedIn && $isAdmin); echo " (&& both? no)\n"; // false
var_export($loggedIn || $isAdmin); echo " (|| either? yes)\n"; // true
var_export(!$isAdmin); echo " (! flip false)\n"; // true
// 'and' / 'or' are word versions that do the same logic BUT bind very loosely —
// looser than '='. This line surprises people:
$result = true and false; // reads as ($result = true) and false -> $result is TRUE
var_export($result); echo " (gotcha: 'and' is looser than '=')\n";
// Use && and || to stay safe. This behaves as expected:
$result = true && false; // $result is FALSE, as you'd hope
var_export($result); echo " (&& binds tighter than '=')\n";
?>false (&& both? no)
true (|| either? yes)
true (! flip false)
true (gotcha: 'and' is looser than '=')
false (&& binds tighter than '=')6️⃣ Null Coalescing & Ternary
These operators let you pick a value in one line. ?? (null coalescing) means "use the left value, but if it's null or unset, use the right" — perfect for defaults, and it won't warn on undefined variables. ??= assigns the fallback only when the variable is currently null. The ternary condition ? a : b is a compact if/else: it returns a when the condition is true, otherwise b. The short ternary ?: returns the left value if it's truthy. The key difference: ?? only reacts to null, while ?: reacts to any falsy value ("", 0, false).
<?php
// ?? NULL COALESCING: "use the left value, but if it's null/unset, use the right."
$username = null;
$name = $username ?? "Guest"; // $username is null, so fall back to "Guest"
echo "name: $name\n"; // name: Guest
// ??= assigns the fallback ONLY if the variable is currently null/unset.
$config = null;
$config ??= "default"; // was null -> becomes "default"
echo "config: $config\n"; // config: default
// TERNARY condition ? valueIfTrue : valueIfFalse — a one-line if/else.
$age = 20;
$status = ($age >= 18) ? "adult" : "minor";
echo "status: $status\n"; // status: adult
// SHORT TERNARY ?: returns the left value if it's "truthy", else the right.
// Careful: ?: checks truthiness ("" and 0 count as false); ?? only checks null.
$nickname = "";
echo "nick: " . ($nickname ?: "Anonymous") . "\n"; // "" is falsy -> Anonymous
?>name: Guest
config: default
status: adult
nick: AnonymousOne more guided exercise. Pick the operator each comment asks for, then run it and compare with the Output panel.
<?php
// 🎯 YOUR TURN — choose the RIGHT comparison operator.
// var_export prints true / false so you can check yourself.
$input = "5"; // came from a form, so it's a STRING "5", not the number 5
// 1) We want this to be FALSE because a string is not the same TYPE as a number.
// Use the STRICT equality operator.
var_export($input ___ 5); echo "\n"; // 👉 replace ___ with strict-equal ( === )
// 2) We want a fallback when $nickname is null. Use null coalescing.
$nickname = null;
echo ($nickname ___ "Guest") . "\n"; // 👉 replace ___ with the ?? operator
// ✅ Expected output:
// false
// Guest
?>false
Guest=== for the strict comparison and ?? for the fallback. The output should be false then Guest.7️⃣ Operator Precedence
Precedence is the order operators run in — exactly like school maths, where * happens before +. So 2 + 3 * 4 is 14, not 20. Comparisons run before && and ||, which is usually what you want. When in any doubt, add parentheses ( ) — they force your order and make intent obvious to the next reader (often future you).
<?php
// PRECEDENCE is the order operators run in, like maths: * before +.
echo 2 + 3 * 4, "\n"; // 14, NOT 20 — * happens before +
// Parentheses ( ) force your own order and make intent obvious.
echo (2 + 3) * 4, "\n"; // 20 — the addition is forced first
// Comparison runs before && / ||, so this reads naturally:
$score = 85;
$pass = $score >= 50 && $score <= 100; // (score>=50) && (score<=100)
var_export($pass); echo "\n"; // true
// When unsure, ADD PARENTHESES. They cost nothing and remove all doubt.
$ok = ($score >= 50) && ($score <= 100);
var_export($ok); echo "\n"; // true
?>14
20
true
trueCommon Errors (and the fix)
- A comparison with
==behaves weirdly — you hit type juggling. With loose==, PHP converts types first, so"5" == 5istrueand other surprises lurk. The fix is almost always to use strict===, which also checks the type. - Your
ifis always true — you wroteif ($x = 5)with one=. A single=assigns 5 to$x(and the result is truthy), so the branch always runs. Comparison needs==or===. "5" + "3"gave8, not"53"— in PHP+is maths only, so it converts numeric strings and adds them. To join text, use the dot:"5" . "3".- Comparing a number to a string of text behaves unexpectedly — mixing types in a comparison is risky. If a value came from a form it's a string; convert it first with
(int)$value(or(float)) before comparing, then use===. $total = $a + $b * 2isn't what you expected — that's precedence:*runs before+. Wrap the part you want first in parentheses:($a + $b) * 2.
Pro Tips
- 💡 Default to
===. Reach for loose==only when you deliberately want type conversion — which is rare. - 💡 Use
??for missing data,?:for "empty-ish" data.??reacts only tonull;?:also catches""and0. - 💡 Stick to
&&/||, not the word forms — their looser precedence causes the$x = true and falsetrap. - 💡 Parentheses are free. When precedence is unclear, add them; readable beats clever.
📋 Quick Reference — PHP Operators
| Operator | Meaning | Example → Result |
|---|---|---|
| + - * / % ** | Arithmetic | 15 % 4 → 3 |
| . .= | String join / append | "Hi " . $name |
| = += -= *= /= | Assign / update | $x += 5 |
| ++ -- | Increment / decrement | $n++ → adds 1 |
| == === | Loose / strict equal | 5 === "5" → false |
| != < > <= >= | Not-equal / ordering | 3 <= 3 → true |
| <=> | Spaceship (3-way) | 1 <=> 5 → -1 |
| && || ! | Logical and / or / not | $a && $b |
| ?? ??= | Null coalescing | $x ?? "default" |
| ? : ?: | Ternary / short ternary | $age >= 18 ? "a" : "b" |
Frequently Asked Questions
Q: What is the difference between == and === in PHP?
== is loose equality: it converts the two values to a common type before comparing, so 5 == "5" is true and (in older PHP) 0 == "" could be true. === is strict equality: the values must match AND be the same type, so 5 === "5" is false because one is an integer and the other a string. Prefer === almost everywhere — it avoids the surprising type-juggling bugs that loose comparison causes.
Q: Why does PHP use a dot (.) to join strings instead of +?
PHP reserves + for arithmetic only, so it picked the dot (.) as the string concatenation operator. This means "5" + "3" gives the number 8 (PHP converts the strings and adds them), while "5" . "3" gives the string "53". If you come from JavaScript or Python where + joins text, this is the single most common mistake — use . for text and += has a text twin called .= .
Q: When should I use ?? versus the short ternary ?: ?
Use ?? (null coalescing) when you only care whether a value is null or unset — $name = $input ?? "Guest" gives "Guest" only when $input is null, and it does not raise a warning for undefined variables. Use ?: (short ternary) when you want the fallback for ANY falsy value, including 0, "", "0", and false. In short: ?? checks for null; ?: checks for truthiness.
Q: What does the spaceship operator <=> do?
The spaceship operator <=> compares two values and returns -1 if the left is smaller, 0 if they are equal, and 1 if the left is larger. It was added in PHP 7 and is mainly used inside sort callbacks: in usort($arr, fn($x, $y) => $x <=> $y) it tells PHP the correct order in a single expression, replacing the older if/elseif comparison code.
Q: Why does my condition behave strangely with 'and' instead of '&&'?
PHP has two AND operators (&& and the word 'and') and two OR operators (|| and 'or'), and they have different precedence. The word versions bind LOOSER than the assignment operator =, so $x = true and false actually runs as ($x = true) and false, leaving $x as true. To avoid this trap, stick to && and || in conditions — they bind tighter than = and behave the way you expect.
Mini-Challenge: Shopping Receipt
No code is filled in this time — just a brief and an outline. Write it yourself, run it on onecompiler.com/php or your own machine, then check your result against the expected output in the comments. This is exactly the write-run-check loop you'll use on every real script.
<?php
// 🎯 MINI-CHALLENGE: A tiny shopping receipt.
// No code is filled in — work from the steps below, then run it.
//
// 1. Make $unitPrice = 12 and $quantity = 4
// 2. Calculate $subtotal (unit price * quantity)
// 3. Calculate $tax = $subtotal * 0.1 (10% tax)
// 4. Calculate $total = $subtotal + $tax
// 5. echo three lines using the . operator, e.g.:
// "Subtotal: " . $subtotal
// Use \n at the end of each so they sit on separate lines.
// 6. Add a discount label with SHORT TERNARY:
// $label = $total > 50 ? "BIG ORDER" : "small order";
//
// ✅ Expected output:
// Subtotal: 48
// Tax: 4.8
// Total: 52.8
// Label: BIG ORDER
// your code here
?>. operator, then pick a label with a ternary. Match the expected output in the comments.🎉 Lesson Complete!
- ✅ Arithmetic uses
+ - * / % **;%is the remainder and/can return a float - ✅ Join text with the dot
.(and append with.=) — never+ - ✅
+= -= ++ --update a variable in place;++$nvs$n++differ by position - ✅ Prefer
===over==— strict equality checks the type too and avoids type-juggling bugs - ✅
<=>compares three ways;&&||!combine conditions - ✅
??/??=give defaults; the ternary?:is a one-line if/else; parentheses settle precedence - ✅ Next lesson: Control Flow — use these comparisons inside
if/elseandswitchto make decisions
Sign up for free to track which lessons you've completed and get learning reminders.