PHP · Beginner
Conditions and Loops in PHP
In short: PHP branches with if, elseif and else, and with the match expression (PHP 8.0), which compares strictly and returns a value. It repeats with while, do...while, for and foreach; break leaves a loop early and continue skips to the next pass. Conditions are evaluated as booleans, and 0, "", "0", null and an empty array all count as false.
Deciding and repeating
A condition is any expression that PHP can treat as true or false. Comparisons produce booleans directly: <, <=, >, >=, ==, ===, != and !==. Other values are converted when they appear in a condition, and the rule is worth memorising: the integer 0, the float 0.0, the empty string, the string "0", null and an empty array are false; everything else, including "false", " " and -1, is true. &&, || and ! combine conditions. (and and or also exist but bind more loosely than =, which causes surprises; stick to the symbols.)
if (condition) { ... } runs its block when the condition holds. elseif adds another test that is only tried when the earlier ones failed, and else catches everything left. Only the first matching branch runs. The braces are optional for a single statement, but always writing them prevents the classic bug where an indented second line looks like part of the branch and is not.
match (PHP 8.0) is an expression: it compares a value against each arm with ===, returns the arm's result, and throws UnhandledMatchError if nothing matches and there is no default arm. Several values can share one arm, separated by commas. It replaces most uses of the older switch, which compares loosely with == and falls through into the next case unless you write break. match (true) with conditions as the arms is a tidy way to write a chain of range checks.
Loops repeat a block. while (condition) tests first and may run zero times; do { } while (condition) runs once before testing. for (start; condition; step) gathers the counter setup, test and increment in one line and suits counting. foreach ($array as $value), or foreach ($array as $key => $value), visits every element of an array and is the loop you will write most. The while (($line = fgets(STDIN)) !== false) form reads input until it runs out; the !== false matters because an empty line is a string that would otherwise look false.
Inside any loop, break leaves it immediately and continue jumps to the next pass. Both accept a number, break 2, to act on an enclosing loop. A loop that never changes the value its condition tests runs forever; when a program on this site hangs, look for the missing increment first.
Syntax
if ($temp < 12) {
// ...
} elseif ($temp <= 26) {
// ...
} else {
// ...
}
$label = match ($code) {
"A", "B" => "group one",
"C" => "group two",
default => "unknown",
};
while ($condition) { ... }
do { ... } while ($condition);
for ($i = 0; $i < 10; $i++) { ... }
foreach ($items as $item) { ... }
foreach ($items as $index => $item) { ... }
break; // leave the loop
continue; // next pass
$sign = $n >= 0 ? "positive" : "negative"; // ternary: a small if in an expressionmatch arms use ===, do not fall through, and the whole match is a value you can assign or echo.
Classifying readings until input ends
Greenhouse temperatures arrive one per line; each is labelled by an if/elseif/else chain.
<?php
while (($line = fgets(STDIN)) !== false) {
$temp = (float) trim($line);
if ($temp < 12) {
$state = "too cold";
} elseif ($temp <= 26) {
$state = "fine";
} else {
$state = "too hot";
}
echo $temp, " C: ", $state, "\n";
}Input given to the program: 9 ↵ 18.5 ↵ 27 ↵ 26
Output
9 C: too cold 18.5 C: fine 27 C: too hot 26 C: fine
The loop condition reads a line and compares it with false in one step; when input is exhausted fgets returns false and the loop ends. The chain tests in order, so 26 reaches the elseif and is fine because the first test failed and 26 <= 26 holds. The float 9 prints as 9, without a decimal point, because PHP drops a zero fraction when printing.
match and a counting loop
A bus timetable maps a day code to a number of departures with match, then a for loop lists the morning buses.
<?php
$days = ["mon", "sat", "sun", "wed"];
foreach ($days as $day) {
$departures = match ($day) {
"mon", "tue", "wed", "thu", "fri" => 12,
"sat" => 8,
"sun" => 4,
};
echo str_pad($day, 4), $departures, " departures\n";
}
for ($hour = 6; $hour <= 9; $hour++) {
echo "Bus at ", $hour, ":00\n";
}Output
mon 12 departures sat 8 departures sun 4 departures wed 12 departures Bus at 6:00 Bus at 7:00 Bus at 8:00 Bus at 9:00
Five weekday codes share one arm, so the match stays short. Because match is an expression, its result is assigned straight to $departures; with switch you would need a break in every case and an assignment in each. There is no default here, so a code such as "hol" would throw UnhandledMatchError, which is usually better than silently doing nothing. The for loop runs four times, for hours 6, 7, 8 and 9, and stops when $hour <= 9 becomes false.
continue, break and do...while
Sensor readings are summed; zero means a missing reading and is skipped, a negative value means a fault and stops the loop.
<?php
$readings = [3, 0, 7, -1, 5, 9];
$total = 0;
foreach ($readings as $r) {
if ($r === 0) {
continue;
}
if ($r < 0) {
echo "Sensor fault, stopping\n";
break;
}
$total += $r;
}
echo "Total: ", $total, "\n";
$attempt = 0;
do {
$attempt++;
echo "Attempt ", $attempt, "\n";
} while ($attempt < 3);Output
Sensor fault, stopping Total: 10 Attempt 1 Attempt 2 Attempt 3
continue skips the rest of the block for the 0, so it is neither added nor treated as a fault. break on the -1 ends the loop before 5 and 9 are seen, which is why the total is 3 + 7 = 10. The do...while prints before it tests, so the body is guaranteed to run at least once; here it runs three times because the test is at the bottom.
Common mistakes
Assignment inside a condition
Why it goes wrong:
if ($status = "open")assigns and then tests the string"open", which is always true. The intended comparison never happens.Fix: Use
==or, better,===. Some people write the constant first,"open" === $status, so a typo becomes a parse error.PHP · fix<?php $status = "closed"; if ($status === "open") { echo "open\n"; }Forgetting break in a switch
Why it goes wrong: After a matching
case, execution continues into the following cases until it meets abreak, so several branches run.Fix: End each case with
break, or usematch, which never falls through.Testing fgets against a truthy value
Why it goes wrong:
while ($line = fgets(STDIN))stops early on a line containing only0, because the string"0"is false.Fix: Compare with
!== falseso only the end of input ends the loop.PHP · fix<?php while (($line = fgets(STDIN)) !== false) { echo trim($line), "\n"; }A loop whose condition never changes
Why it goes wrong:
while ($i < 5) { echo $i; }without$i++prints forever and the program is killed for exceeding its time limit.Fix: Make sure something in the body moves the condition towards false, or use
forso the step is written next to the test.
Values that count as false in a condition
| Value | In a condition | Note |
|---|---|---|
| 0, 0.0, -0.0 | false | any other number, including -1, is true |
| "" and "0" | false | "0.0", " " and "false" are true |
| null | false | also what an unset variable yields |
| [] | false | an array with any element, even [0], is true |
| false | false | true is true |
Where you use this
Nearly every exercise combines one loop that reads input with one condition that decides what to do with each line: count the values above a threshold, stop at a sentinel, or classify each record. The read-until-false loop and the for loop over a known count are the two input shapes you will see again and again, and match (true) is the clean way to turn a number into a category name when the categories are ranges rather than exact values.
$band = match (true) {
$score >= 90 => "gold",
$score >= 70 => "silver",
default => "bronze",
};Key points
if/elseif/elseruns the first branch whose condition is true; always use braces.matchcompares with===, returns a value, has no fallthrough and throws if nothing matches.whiletests first,do...whiletests after,forbundles counter setup, test and step.foreachis the natural way to visit every array element, with or without keys.- Read input with
while (($line = fgets(STDIN)) !== false). breakleaves the loop,continueskips to the next pass; a number targets an outer loop.- 0, 0.0, "", "0", null and [] are false; everything else is true.
Try it yourself
The program reads a count and then that many integers, but never counts anything. Complete the loop so it counts the even numbers and prints the count.
<?php
$n = (int) trim(fgets(STDIN));
$evens = 0;
for ($i = 0; $i < $n; $i++) {
$value = (int) trim(fgets(STDIN));
// increase $evens when $value is even
}
echo $evens, "\n";
5 ↵ 4 ↵ 7 ↵ 10 ↵ 3 ↵ 83<?php
$n = (int) trim(fgets(STDIN));
$evens = 0;
for ($i = 0; $i < $n; $i++) {
$value = (int) trim(fgets(STDIN));
if ($value % 2 === 0) {
$evens++;
}
}
echo $evens, "\n";
Practise this
- Fewest charging stops for the vanHard
Plan the minimum charging stops for an electric van on a straight route with a greedy choice in PHP, or report that the trip is impossible.
Control flowNot started
- Vaccine fridge statusEasy
Classify a fridge temperature reading as OK, TOO COLD or TOO WARM with if, elseif and else in PHP. Practise comparisons on decimal input.
Control flowNot started
Related lessons
- Variables and Types in PHPHow PHP variables are named and assigned, the scalar types int, float, string, bool and null, how input text becomes numbers, and where type juggling bites.8 min
- Functions in PHPDefine PHP functions with typed parameters and return types, use default values, named arguments and variadics, and see why variables inside a function are.10 min
- Arrays in PHPHow PHP arrays hold ordered lists: literals, indexing, appending, count, foreach, searching, slicing and the array_map, array_filter and array_sum helpers.9 min
Frequently asked questions
What is the difference between match and switch in PHP?
match (PHP 8.0) is an expression that returns a value, compares with ===, allows several values per arm, never falls through, and throws UnhandledMatchError when no arm matches and there is no default. switch is a statement, compares with ==, and continues into the next case unless each one ends with break. Prefer match for mapping a value to a result; use switch only when a branch must run several statements and you want the older, looser behaviour.
Is the string "0" true or false in PHP?
False. The only strings that are false in a condition are the empty string and "0". "0.0", "false" and a single space are all true. This is why input loops should compare fgets with !== false instead of relying on truthiness.
When should I use foreach instead of for?
Use foreach whenever you want every element of an array, in order; it needs no counter and cannot run past the end. Use for when you are counting rather than visiting, for example reading exactly $n lines of input, or when you need to step by more than one or walk backwards.
How this page was checked. Every program on it was run with PHP 8.4 at build time by the publishing checks, and the output shown is what it printed. Running PHP inside the browser is not available yet, so the Run button is absent rather than pretending; copy the code and run it with PHP 8.4 locally.