Lesson 4 • Beginner
Control Flow 🔀
By the end of this lesson you'll make your PHP make decisions — branching with if, choosing between many options with switch and the safer PHP 8 match, and writing tidy one-liners with the ternary and template if: ... endif; syntax.
What You'll Learn in This Lesson
- Branch with if / elseif / else and pick the first true block
- Combine conditions with && (and) and || (or)
- Match one value against many options with switch and break
- Use the PHP 8 match expression — strict, and it returns a value
- Write compact choices with the ternary ? : and null-coalescing ??
- Use the alternative if: ... endif; syntax inside HTML templates
$score >= 70 or $x == 5 looks unfamiliar, run through Operators & Expressions first, then come back here.php file.php. The Output panel under each example shows exactly what to expect.if is a lever for a yes/no fork; switch and match are a turntable that sends the train down whichever of many tracks matches the label it's carrying.1️⃣ if / elseif / else
An if statement runs a block of code only when its condition is true. A condition is any expression that's true or false — usually a comparison like $score >= 70. Add elseif branches to test more conditions, and a final else as the catch-all. PHP checks them top to bottom and runs only the first block that's true, then skips the rest — so order matters. You can join conditions with && (both must be true) and || (either is enough).
<?php
// if / elseif / else — PHP runs the FIRST block whose condition is true,
// then skips the rest. Conditions use comparison operators like >= and == .
$score = 78;
echo "Student score: $score\n";
if ($score >= 90) {
echo "Grade: A\n"; // skipped: 78 is not >= 90
} elseif ($score >= 80) {
echo "Grade: B\n"; // skipped: 78 is not >= 80
} elseif ($score >= 70) {
echo "Grade: C\n"; // ✅ true! 78 >= 70 — this runs, rest skipped
} else {
echo "Grade: F\n"; // the catch-all when nothing above matched
}
// Combine conditions with && (AND) and || (OR).
$isWeekend = true;
$temperature = 28;
if ($isWeekend && $temperature > 25) { // BOTH must be true
echo "Beach day!\n";
} elseif ($isWeekend || $temperature > 30) { // EITHER is enough
echo "Day off, but cool\n";
} else {
echo "A normal day\n";
}
?>Student score: 78
Grade: C
Beach day!Note that PHP spells it elseif as one word (else if as two words also works). Because only the first true branch runs, the score 78 prints "Grade: C" and never even checks the lower branches.
2️⃣ switch / case / break / default
When you're comparing one value against a list of fixed options, a long if/elseif chain gets noisy. A switch reads better: you name the value once, then list each possible case. The crucial part is break — it tells PHP to stop once a case has run. Leave it out and PHP "falls through" into the next case and keeps going. default is the catch-all (like else), and you can stack cases to share one block.
<?php
// switch — compare ONE value against many fixed options.
// Each 'case' is a possible value; 'break' stops PHP falling into the next case.
$day = 3; // 1 = Monday ... 7 = Sunday
echo "Day number: $day\n";
switch ($day) {
case 1:
echo "Monday\n";
break; // stop here — don't run case 2
case 6:
case 7: // stacked cases: 6 OR 7 run the same block
echo "Weekend!\n";
break;
default: // runs when no case matched (here: 2,3,4,5)
echo "A weekday\n"; // ✅ $day is 3, so this runs
// no break needed on the LAST case, but it's tidy to add one
}
?>Day number: 3
A weekday3️⃣ The PHP 8 match Expression
match (added in PHP 8) is a sharper switch. Three things make it nicer: it returns a value you can assign straight to a variable; it needs no break because it never falls through; and it compares with strict ===, so the integer 200 won't accidentally match the string "200". Each arm is value => result, arms are separated by commas, and one arm can list several values. Prefer match over switch for simple value-to-value mapping in PHP 8+.
<?php
// match (PHP 8) — like switch, but it RETURNS a value and uses strict
// comparison (===), so 200 only matches the integer 200, never "200".
// No 'break' needed, and commas separate the arms.
$httpCode = 404;
$message = match ($httpCode) {
200, 201 => "Success", // one arm can list several values
301, 302 => "Redirect",
404 => "Not Found", // ✅ matches — this value is returned
500 => "Server Error",
default => "Unknown", // used if nothing else matched
};
echo "HTTP $httpCode: $message\n"; // the returned value lands in $message
?>HTTP 404: Not Found4️⃣ Ternary ? : and Null-Coalescing ??
When a choice is small, a full if/else is overkill. The ternary operator packs it into one line that produces a value: condition ? ifTrue : ifFalse. Closely related is null coalescing ??, which says "use the left value, or this fallback if the left is null or unset" — perfect for safe defaults like a guest name when no one is logged in. Keep ternaries to genuinely simple choices; nesting them quickly becomes unreadable.
<?php
// Ternary condition ? valueIfTrue : valueIfFalse — a one-line if/else
// that produces a VALUE. Great for picking between two options.
$age = 20;
$status = ($age >= 18) ? "Adult" : "Minor"; // 20 >= 18 → "Adult"
echo "Status: $status\n";
// ?? is the 'null coalescing' operator: "use the left value, OR this
// fallback if the left is null / not set". Handy for safe defaults.
$username = null;
$display = $username ?? "Guest"; // $username is null → "Guest"
echo "Welcome, $display\n";
?>Status: Adult
Welcome, Guest5️⃣ Alternative if: ... endif; Syntax
PHP offers a second way to write control structures: drop the curly braces, put a colon after the condition, and close with an endif; keyword (there's also endswitch;, endwhile;, and so on). It behaves exactly like the brace version. Its purpose is readability in templates — when you weave PHP through chunks of HTML, a matching endif; is far easier to spot than a lonely } buried in markup.
<?php
// Alternative syntax: swap the { } braces for a colon and an 'end...' keyword.
// It reads cleanly when you weave PHP through HTML in a template.
$loggedIn = true;
?>
<?php if ($loggedIn): ?>
<p>Welcome back!</p>
<?php else: ?>
<p>Please log in.</p>
<?php endif; ?> <p>Welcome back!</p>Because $loggedIn is true, only the first block's HTML is sent; the else markup is skipped entirely.
6️⃣ Your Turn — Fill in the Blanks
Time to practise. Each script below is almost complete — replace every ___ using the 👉 hint, then run it and check it against the Output panel.
<?php
// 🎯 YOUR TURN — finish the if/elseif/else, then run it.
// Pick the band the temperature falls into.
$temp = 30;
if ($temp >= 30) {
echo ___; // 👉 "Hot\n"
} elseif (___) { // 👉 condition for 20 or above: $temp >= 20
echo "Warm\n";
} else {
echo "Cool\n";
}
// ✅ Expected output (with $temp = 30):
// Hot
?>Hot___ blanks — an echo value and a comparison condition. With $temp = 30 the output should be one line: Hot.Now a match. Fill in the missing result and the catch-all keyword so it returns the right label.
<?php
// 🎯 YOUR TURN — complete this match so it returns the right label.
// Remember: match uses value => result arms and needs a default.
$grade = "B";
$label = match ($grade) {
"A" => "Excellent",
"B" => ___, // 👉 "Good"
"C" => "Okay",
___ => "Unknown grade", // 👉 the catch-all keyword: default
};
echo "Grade $grade: $label\n";
// ✅ Expected output:
// Grade B: Good
?>Grade B: Good___ with the result for "B", and the second with the catch-all keyword default. Output: Grade B: Good.Common Errors (and the fix)
- A switch runs the wrong (or every) case — you forgot a
break. Without it, PHP keeps running into the next case after a match ("fall-through"). Put abreak;at the end of every case, or switch tomatch, which never falls through. - "UnhandledMatchError: Unhandled case" — your
matchhad no arm for the value and nodefault. Unlike switch, match refuses to silently do nothing. Add adefault => ...arm to catch anything you didn't list. - A comparison passes when it shouldn't — you used loose
==, which converts types first, so0 == "hello"can be true in old PHP and"5" == 5is true. Use strict===in conditions to compare value and type. - An
ifalways runs, no matter the value — you wroteif ($x = 5)with one=. That assigns 5 to$x(a truthy result) instead of comparing. To compare, use two equals:if ($x == 5)(or===).
Pro Tips
- 💡 Default to
matchfor value-to-value mapping in PHP 8+ — nobreak, strict comparison, and it returns a value you can assign. - 💡 Always add a
defaultto amatch(and usually a switch) so unexpected values are handled, not crashing or silently ignored. - 💡 Use
===in conditions. Strict comparison avoids PHP's loose-typing surprises and makes your intent obvious. - 💡 Keep ternaries simple. One
? :is readable; nested ternaries are not — reach for a full if/else instead.
📋 Quick Reference — Control Flow
| Structure | Example | Use When |
|---|---|---|
| if / elseif / else | if ($n > 0) { ... } | Different conditions to test, in order |
| switch | switch ($x) { case 1: ... break; } | One value vs many fixed options |
| match | match ($x) { 1 => "a", default => "b" } | Map a value to a value (PHP 8+, strict) |
| ? : | $ok ? "yes" : "no" | A simple one-line either/or value |
| ?? | $name ?? "Guest" | A default when the value is null/unset |
| if: ... endif; | if ($ok): ?> ... <?php endif; | Mixing PHP with HTML in templates |
Frequently Asked Questions
Q: When should I use match instead of switch in PHP?
Reach for match (PHP 8+) whenever you are picking a value from a fixed set of options. It is shorter, needs no break statements, compares strictly with === so 200 never matches the string "200", and it returns a value you can assign straight to a variable. Use switch when you need to run several statements per branch or you are targeting PHP 7, where match does not exist.
Q: What is the difference between == and === in conditions?
== compares values after PHP converts types for you, so 0 == "0" and even 0 == "" can surprise you. === compares value AND type, so "5" === 5 is false. Prefer === in your if conditions: it is predictable and avoids the loose-comparison traps that bite beginners. match() always uses === for you.
Q: Why does my switch run more than one case?
You almost certainly forgot a break. Without break, PHP keeps running the next case's code too — called fall-through. Sometimes that is intentional (stacking case 6: case 7: to share a block), but usually it is a bug. Put a break at the end of every case, or switch to match(), which never falls through.
Q: What happens if match has no matching arm and no default?
PHP throws an UnhandledMatchError and stops. Unlike switch, match refuses to silently do nothing — it forces you to handle every case. Add a default => arm to catch anything you did not list, exactly like the else on an if. This strictness is a feature: it surfaces values you forgot to handle.
Q: What is the if: ... endif; syntax for?
It is the alternative syntax: replace the { } braces with a colon after the condition and an endif; (or endswitch;, endwhile;) keyword to close. It behaves identically to the brace version. Its purpose is readability inside HTML templates, where opening and closing PHP tags around lots of markup makes stray braces easy to lose.
Mini-Challenge: Ticket Price
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 decide-run-check loop you'll use on every real script.
<?php
// 🎯 MINI-CHALLENGE: a tiny ticket-price calculator.
// No code is filled in — work from the steps, then run it.
//
// 1. Set $age to a number (try 12).
// 2. Use if/elseif/else to choose a price:
// under 5 → "Free"
// 5 to 17 → "Child: $8"
// 18 and over → "Adult: $15"
// 3. echo the result on its own line.
//
// Tip: order matters — test the smallest range first, or use ranges
// like ($age >= 5 && $age <= 17).
//
// ✅ Expected output (with $age = 12):
// Child: $8
// your code here
?>$age = 12 the output should be a single line: Child: $8.🎉 Lesson Complete!
- ✅
if / elseif / elseruns the first true branch; combine conditions with&&and|| - ✅
switchcompares one value to many cases — and every case needs abreak - ✅
match(PHP 8) returns a value, uses strict===, and throws if nothing matches and there's nodefault - ✅ The ternary
? :and null-coalescing??give you compact one-liners - ✅ The alternative
if: ... endif;syntax keeps PHP-in-HTML templates readable - ✅ Prefer
===in conditions, and watch the single=assignment trap - ✅ Next lesson: Loops — repeat code with
for,while, andforeach
Sign up for free to track which lessons you've completed and get learning reminders.