PHP Phase 3: Operators — Arithmetic, Comparison, Logical & More

PHP Phase 3: Operators — Arithmetic, Comparison, Logical & More

Phase 3 — Operators

1. What Is It?

An operator is a symbol that tells PHP to perform a specific operation on one or more values (called operands), producing a result.

2. Why Does It Exist?

Variables and literals alone just hold data — operators are how you actually do something with that data: combine numbers, compare values, chain logical conditions, build strings. Without operators, a program could store information but never transform or reason about it.

3. How It Works (Conceptual)

When PHP encounters an expression like $a + $b, it evaluates both operands to their current values, then applies the operation associated with +, producing a new value — which itself can be stored, compared, or used in a further expression. Operators are one of the building blocks of expressions (anything that evaluates to a value), which combine to form statements.


Arithmetic Operators

OperatorMeaningExampleResult
+Addition5 + 38
-Subtraction5 - 32
*Multiplication5 * 315
/Division5 / 31.666...
%Modulo (remainder after division)5 % 32
**Exponentiation (power)5 ** 225

Modulo — Deserves a Real Explanation

What it is: % returns the remainder left over after dividing the first number by the second.

Why it exists: It's the standard tool for answering "does this number divide evenly into that one?" or "what's left over?" — used constantly for things like checking even/odd, cycling through a fixed range of values, pagination math.

echo 10 % 3; // 1 → 10 = 3*3 + 1 echo 9 % 3; // 0 → 9 divides evenly, no remainder echo 7 % 2; // 1 → odd number echo 8 % 2; // 0 → even number

Real-world example:

$number = 7; if ($number % 2 === 0) { echo "Even"; } else { echo "Odd"; }

Exponentiation

echo 2 ** 10; // 1024 echo 5 ** 2; // 25
🔄 Version note: ** was introduced in PHP 5.6. Before that, you had to use pow(5, 2) — that function still exists and still works, but ** is the modern preferred syntax.

Common Mistake — Integer vs Float Division

(Recap from 2.3, now formalized as an operator behavior)

var_dump(10 / 2); // int(5) var_dump(10 / 3); // float(3.3333333333333)

Assignment Operators

1. What Is It?

Assignment operators store a value into a variable. Compound assignment operators combine an arithmetic (or string) operation with assignment in one step.

OperatorEquivalent ToExample
=— (base assignment)$x = 5;
+=$x = $x + y$x += 3;
-=$x = $x - y$x -= 3;
*=$x = $x * y$x *= 3;
/=$x = $x / y$x /= 3;
%=$x = $x % y$x %= 3;
**=$x = $x ** y$x **= 2;
$score = 10; $score += 5; // $score is now 15 $score -= 2; // $score is now 13 $score *= 2; // $score is now 26

Why they exist: $total += $item; is shorter, and arguably clearer in intent ("increase total by item") than $total = $total + $item;. This is not just typing convenience — it's a widely recognized idiom, and reading += immediately signals "accumulation" to an experienced developer.

When to use: Any time you're updating a variable based on its own current value — running totals, counters, accumulating strings.


Comparison Operators

This section matters enormously in PHP specifically, because of everything you learned in Phase 2.4 about type juggling.

OperatorMeaning
==Equal (loose — allows type juggling)
===Identical (strict — types must match too)
!=Not equal (loose)
<>Not equal (loose, older alternate syntax, rarely used)
!==Not identical (strict)
<Less than
>Greater than
<=Less than or equal
>=Greater than or equal
<=>Spaceship (three-way comparison)

== vs === — The Comparison You MUST Internalize

== (loose equality): Compares values, allowing type juggling to happen first if the types differ, then compares the (possibly converted) values.

=== (strict equality): Compares both value AND type. If the types differ at all, the result is immediately false — no conversion attempted.

var_dump(5 == "5"); // true — "5" is juggled to int 5, then 5 == 5 var_dump(5 === "5"); // false — different types (int vs string), // no juggling allowed, immediately false var_dump(0 == false); // true — false juggled toward comparison, matches var_dump(0 === false); // false — int vs bool, different types var_dump(null == false); // true — both "falsy," loose comparison passes var_dump(null === false); // false — null and bool are different types

Why This Matters So Much in Real Code

$position = strpos("Hello World", "Hello"); // returns 0 (found at index 0) if ($position == false) { echo "Not found"; // THIS RUNS — WRONG! It WAS found, at position 0! }

What went wrong: strpos() returns the numeric position where a substring is found — and 0 is a perfectly valid "found at the very start" result. But 0 == false is true (loose comparison), so this buggy code incorrectly reports "not found" whenever the match happens to be at position 0. The correct version:

if ($position === false) { echo "Not found"; // Only true if strpos() ACTUALLY returned the boolean false }

This single example is one of the most cited real-world justifications for defaulting to === in PHP. I want you to internalize this now: default to === and !== unless you have a specific, deliberate reason to allow type juggling.

The Spaceship Operator <=>

What it is: Returns -1, 0, or 1 depending on whether the left operand is less than, equal to, or greater than the right operand.

echo 1 <=> 2; // -1 (1 is less than 2) echo 2 <=> 2; // 0 (equal) echo 3 <=> 2; // 1 (3 is greater than 2)

Why it exists: Its primary real use is inside custom sorting functions (you'll meet this properly in Phase 7 with usort()), where a comparator needs to return exactly this kind of three-way signal:

$numbers = [5, 2, 8, 1]; usort($numbers, fn($a, $b) => $a <=> $b); // ascending sort

You don't need to fully grasp usort yet — just recognize the spaceship operator's shape and purpose; we'll use it concretely in Phase 7.


Logical Operators

OperatorMeaning
&&AND (both must be true)
||OR (at least one must be true)
!NOT (inverts a boolean)
andAND (word form — lower precedence, see below)
orOR (word form — lower precedence, see below)
xorExclusive OR (true if exactly one side is true, not both)
$isAdult = true; $hasID = false; var_dump($isAdult && $hasID); // false — both required, one is false var_dump($isAdult || $hasID); // true — only one required, one is true var_dump(!$isAdult); // false — inverts true to false var_dump(true xor false); // true — exactly one is true var_dump(true xor true); // false — both true, xor requires EXACTLY one

&&/|| vs and/or — Real, Important Difference (Not Stylistic)

They perform the same logical operation, but have drastically different operator precedence (which we formalize fully at the end of this phase). The critical practical trap:

$result = false or true; var_dump($result); // bool(false) !!

Why this surprises everyone: = has higher precedence than or. So this line is actually parsed as ($result = false) or true$result gets assigned false first, and the or true part is evaluated but its result is simply discarded. Compare:

$result = false || true; var_dump($result); // bool(true) — correct, as expected

Here, || has higher precedence than =, so it's parsed as $result = (false || true), which correctly evaluates the OR first, then assigns the result.

Practical guidance: Use && and || in essentially all real conditional logic. The word forms and/or/xor exist mainly for a narrow, rarely-needed control-flow idiom ($result = someFunction() or die("failed");) that you don't need as a beginner. Default to the symbol forms, always.

Increment / Decrement Operators

1. What Is It?

++ and -- increase or decrease a variable's value by exactly 1.

3. How It Works — Prefix vs Postfix

(This distinction genuinely matters)

$a = 5; echo $a++; // outputs 5 (the ORIGINAL value), THEN increments $a to 6 echo $a; // 6 $b = 5; echo ++$b; // increments $b to 6 FIRST, THEN outputs 6 echo $b; // 6
  • Postfix ($a++): "Use the current value in this expression right now, then increment afterward."
  • Prefix (++$a): "Increment first, then use the new value in this expression."

If the increment stands alone on its own line, prefix and postfix produce an identical end result — the distinction only matters when the increment is used as part of a larger expression (like inside echo, or as a function argument, or inside array indexing).

$count = 0; $count++; // just increments to 1 — prefix vs postfix makes no visible difference here

Real-world use: loop counters (Phase 5), which is by far the most common place you'll actually use these operators.


String Operators

OperatorMeaning
.Concatenation (joins two strings)
.=Concatenation assignment
$firstName = "Raja"; $lastName = "Kumar"; $fullName = $firstName . " " . $lastName; echo $fullName; // Raja Kumar
$message = "Hello"; $message .= ", "; $message .= "World!"; echo $message; // Hello, World!

Common Mistake — Confusing . with +

echo "5" + "3"; // 8 — treated as NUMBERS (arithmetic addition, type juggled) echo "5" . "3"; // 53 — treated as TEXT (concatenation)

This is a very common source of confusion for people coming from languages like JavaScript, where + does both jobs depending on context. In PHP, + is exclusively arithmetic, and . is exclusively concatenation — they are never interchangeable.


Conditional Operators

Ternary Operator

What it is: A compact, single-expression form of an if/else that produces a value.

$age = 20; $status = ($age >= 18) ? "Adult" : "Minor"; echo $status; // Adult

Syntax breakdown:

condition ? valueIfTrue : valueIfFalse

Why it exists: For simple two-branch decisions producing a value, writing a full if/else block is verbose. The ternary compresses it into one readable line — but only when both branches are simple.

Shorthand ternary (?:):

$username = $inputName ?: "Guest"; // equivalent to: $inputName ? $inputName : "Guest" // if $inputName is truthy, use it; otherwise use "Guest"

Null Coalescing Operator ??

What it is: Returns the left operand if it exists and is not null; otherwise returns the right operand.

$username = $_GET['username'] ?? "Guest";

Critical distinction from ?:: ?? specifically checks for null / "does not exist" (technically, it uses isset()-like semantics internally — it won't throw a warning even if the variable doesn't exist at all, unlike normal variable access). The shorthand ternary ?: checks truthiness, which is a much broader and looser check.

$value = "0"; echo $value ?: "default"; // "default" — "0" is FALSY, so ternary falls through echo $value ?? "default"; // "0" — "0" is NOT NULL, so null coalescing keeps it
This is an important, real difference. If a field legitimately might be 0, "0", false, or "" as a valid value (not an error state), and you only want to substitute a default when the value is truly absent/null, use ??, not ?:.

Null Coalescing Assignment ??=

$config['theme'] ??= "light"; // equivalent to: // if (!isset($config['theme'])) { $config['theme'] = "light"; }

Assigns only if the variable is currently null/unset — very handy for setting defaults without overwriting an already-present value.

Nullsafe Operator ?->

🔄 Version note: Introduced in PHP 8.0. This relates to objects (Phase 2.3, briefly touched, full depth after this course). I'll explain it at a conceptual level since it's explicitly in your curriculum.
$name = $user?->profile?->name;

What it does: Normally, if $user were null, trying $user->profile would throw a fatal error ("attempt to read property on null"). The nullsafe operator ?-> says: "if the thing on the left is null, stop immediately and the whole expression evaluates to null — don't throw an error, don't try to continue accessing ->name."

Why it exists: Avoids writing verbose defensive chains like:

$name = null; if ($user !== null) { if ($user->profile !== null) { $name = $user->profile->name; } }

replaced by one line: $user?->profile?->name;

You'll use this meaningfully once we cover OOP — for now, just recognize the syntax and its purpose.


Operator Precedence

1. What Is It?

Precedence determines which operators are evaluated first when an expression contains multiple operators, in the absence of explicit parentheses.

2. Why Does It Exist?

Without a fixed rule, 2 + 3 * 4 would be ambiguous — is it (2+3)*4 = 20 or 2+(3*4) = 14? Every programming language (and mathematics itself) needs a defined precedence order so expressions have exactly one correct interpretation.

3. How It Works

echo 2 + 3 * 4; // 14, NOT 20

Why: * has higher precedence than +, so PHP evaluates 3 * 4 first (= 12), then 2 + 12 = 14. This mirrors standard mathematical order of operations (the same reason "multiplication before addition" is taught in school).

echo (2 + 3) * 4; // 20 — parentheses OVERRIDE default precedence, // forcing the addition to happen first

Key partial precedence table (high to low, simplified for what you know so far):

** (exponentiation) ! (unary not), ++, -- (unary operators) *, /, % (multiplication tier) +, -, . (addition/subtraction/concat tier) <, <=, >, >= (relational) ==, !=, ===, !==, <=> (equality) && (logical and) || (logical or) ?? (null coalescing) = += -= *= /= .= etc. (assignment — very low precedence!) and (even lower than =) xor or (lowest of all)
Practical rule I want you to actually follow, not just know: When any expression mixes more than two operators, or mixes different operator categories, use parentheses — even when you're fairly sure you know the precedence. This isn't laziness — it makes the code's intent immediately obvious to anyone reading it (including future-you), rather than requiring them to mentally recompute a precedence table.
technically correct, but relies on the reader knowing precedence:
$result = $a + $b * $c > $d && $e;
vastly clearer:
$result = ($a + ($b * $c)) > $d && $e;

12. Edge Cases (Cross-Cutting, Whole Phase)

var_dump("10" <=> "9"); // 1 — numeric strings compared numerically (10 > 9) var_dump("abc" <=> "abd"); // -1 — non-numeric strings compared as plain text/lexically var_dump(1 <=> "1"); // 0 — loose-style comparison rules apply here too (int vs numeric string)
$a = 5; $b = $a++ + ++$a; // $a++ uses 5, then $a becomes 6 // ++$a increments $a to 7 first, then uses 7 // $b = 5 + 7 = 12, and $a ends at 7 var_dump($b); // 12 var_dump($a); // 7

I'd strongly discourage ever writing real code like this line — it's shown purely so you understand why mixing prefix/postfix in a single compound expression is confusing and should be avoided in practice, not something to emulate.

13. Related Concepts

Comparison operators directly extend Phase 2.4 (type juggling). Logical operators feed directly into Phase 4 (Conditions), where you'll combine them inside if statements. The ternary and null coalescing operators are compact alternatives to full if/else, which is exactly what Phase 4 formally teaches next.


Knowledge Check — Phase 3

A. Concept Questions

  1. What is the actual mechanical difference between == and ===?
  2. Why did the strpos() example break with == but work correctly with ===?
  3. What's the real difference between ?? and ?:? Give an example where they'd produce different results.
  4. Why is $result = false or true; a trap? What does $result actually end up holding?
  5. What does the spaceship operator return, and in what three cases?
  6. Why is + never used for string concatenation in PHP, unlike some other languages?
  7. What's the difference between $a++ and ++$a when used inline in a larger expression?

B. Code Prediction

Predict the output of each line before running:

var_dump(10 % 3); var_dump("10" == "1e1"); var_dump("10" === "1e1"); var_dump(5 + "5 bananas"); // consider the PHP 8 behavior discussed above var_dump("abc" <=> "abd"); var_dump(null ?? false ?? "default"); $x = 4; var_dump($x++ + $x++);

C. Debugging Challenge

This code is meant to check if a discount code was found at any position in a string (including position 0), and print "Found" or "Not found" accordingly. Find the bug and fix it:

<?php $code = "SAVE10"; $position = strpos($code, "SAVE"); if ($position == false) { echo "Not found"; } else { echo "Found at position " . $position; }

D. Practical Challenge

Write a small script that:

  1. Declares two numeric variables (you choose values).
  2. Uses the ternary operator to determine and print which is larger (or if they're equal).
  3. Uses % to determine and print whether their sum is even or odd.
  4. Uses the null coalescing operator to safely handle a third variable, $discountCode, that may or may not be set (test it both ways — once defined, once not, using isset()-safe access — you can simulate "not set" simply by commenting out its definition).

Comments (0)

Leave a Comment

FROM CONCEPT TO CREATION

LET's MAKE IT HAPPEN!

I'm available for full-time roles & freelance projects.

I thrive on crafting dynamic web applications, and delivering seamless user experiences.