Beginner

Control Flow in PHP

Learn conditionals, loops, and decision-making in PHP with if/else, match, for, while, and foreach using Docker-ready examples

Control flow is how a program decides what to do next. Instead of running every line top to bottom, control flow lets PHP branch on conditions, repeat work, and short-circuit logic. These constructs are the backbone of every PHP request that renders a page, validates a form, or loops over database rows.

As a multi-paradigm language with dynamic, weak typing, PHP gives you the familiar C-style toolkit — if/elseif/else, for, while, do-while, switch, and break/continue — alongside modern additions like the match expression (PHP 8.0) and the null coalescing operator (??). Because PHP is weakly typed, conditions coerce values to booleans following specific “truthiness” rules, which is worth understanding early.

In this tutorial you’ll work through conditionals, the match expression, every loop type, loop control, and the concise ternary and null-coalescing operators. Each example is a complete, runnable script.

Conditionals: if, elseif, else

The if statement runs a block only when a condition evaluates to true. PHP coerces the condition to a boolean, so 0, 0.0, "", "0", null, and empty arrays are all “falsy.”

Create a file named conditionals.php:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
$score = 82;

if ($score >= 90) {
    echo "Grade: A\n";
} elseif ($score >= 80) {
    echo "Grade: B\n";
} elseif ($score >= 70) {
    echo "Grade: C\n";
} else {
    echo "Grade: F\n";
}

// Truthiness: weak typing coerces values to booleans
$input = "0";
if ($input) {
    echo "Truthy\n";
} else {
    echo "Falsy: the string \"0\" is considered false\n";
}

// Logical operators combine conditions
$age = 25;
$hasTicket = true;
if ($age >= 18 && $hasTicket) {
    echo "Entry granted\n";
}

The match Expression

Introduced in PHP 8.0, match is a modern alternative to switch. It uses strict comparison (===), returns a value, and requires no break statements. Unlike switch, it does not fall through.

Create a file named match_expression.php:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
$statusCode = 404;

$message = match ($statusCode) {
    200, 201 => "Success",
    301, 302 => "Redirect",
    404      => "Not Found",
    500      => "Server Error",
    default  => "Unknown Status",
};

echo "Status $statusCode: $message\n";

// match with no argument acts like chained if/elseif
$temp = 30;
$label = match (true) {
    $temp < 0   => "Freezing",
    $temp < 15  => "Cold",
    $temp < 25  => "Mild",
    default     => "Warm",
};

echo "Temperature $temp is $label\n";

Loops: for, while, do-while

PHP supports the classic C-style loops. for is ideal when you know the iteration count, while checks its condition before each pass, and do-while always runs at least once.

Create a file named loops.php:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
// for loop: counts from 1 to 5
echo "for loop: ";
for ($i = 1; $i <= 5; $i++) {
    echo $i . " ";
}
echo "\n";

// while loop: runs while the condition holds
echo "while loop: ";
$n = 10;
while ($n > 0) {
    echo $n . " ";
    $n -= 2;
}
echo "\n";

// do-while loop: body runs at least once
echo "do-while loop: ";
$count = 0;
do {
    echo "run($count) ";
    $count++;
} while ($count < 3);
echo "\n";

Iterating with foreach

The foreach loop is PHP’s idiomatic way to walk arrays — both indexed (list-style) and associative (key/value maps). It’s the loop you’ll reach for most often in real PHP code.

Create a file named foreach_loop.php:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<?php
// Indexed array
$languages = ["PHP", "Python", "Rust"];
foreach ($languages as $language) {
    echo "Language: $language\n";
}

// Associative array with key => value
$versions = [
    "PHP"    => "8.4",
    "Python" => "3.13",
    "Rust"   => "1.85",
];
foreach ($versions as $name => $version) {
    echo "$name is at version $version\n";
}

Loop Control: break and continue

break exits a loop entirely, while continue skips to the next iteration. Both accept an optional level argument to control nested loops.

Create a file named loop_control.php:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?php
// continue: skip even numbers, print only odd ones
echo "Odd numbers: ";
for ($i = 1; $i <= 10; $i++) {
    if ($i % 2 === 0) {
        continue;
    }
    echo $i . " ";
}
echo "\n";

// break: stop at the first number over 3
echo "Searching: ";
foreach ([1, 2, 3, 4, 5] as $value) {
    if ($value > 3) {
        echo "found $value, stopping\n";
        break;
    }
    echo "$value ";
}

Ternary and Null Coalescing

For concise decisions, PHP offers the ternary operator (?:) and the null coalescing operator (??), which returns the first operand that exists and is not null.

Create a file named concise_conditions.php:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<?php
// Ternary operator: condition ? if-true : if-false
$balance = 0;
$status = $balance > 0 ? "In credit" : "Empty or overdrawn";
echo "Account: $status\n";

// Short ternary (Elvis operator): returns left side if truthy
$username = "";
$display = $username ?: "Guest";
echo "Welcome, $display\n";

// Null coalescing: use a default when a value is null or unset
$config = ["theme" => "dark"];
$theme = $config["theme"] ?? "light";
$lang = $config["lang"] ?? "en";
echo "Theme: $theme, Language: $lang\n";

Running with Docker

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Pull the official PHP CLI image
docker pull php:8.4-cli-alpine

# Run each example
docker run --rm -v $(pwd):/app -w /app php:8.4-cli-alpine php conditionals.php
docker run --rm -v $(pwd):/app -w /app php:8.4-cli-alpine php match_expression.php
docker run --rm -v $(pwd):/app -w /app php:8.4-cli-alpine php loops.php
docker run --rm -v $(pwd):/app -w /app php:8.4-cli-alpine php foreach_loop.php
docker run --rm -v $(pwd):/app -w /app php:8.4-cli-alpine php loop_control.php
docker run --rm -v $(pwd):/app -w /app php:8.4-cli-alpine php concise_conditions.php

Running Locally

If you have PHP installed:

1
php conditionals.php

Expected Output

Running conditionals.php:

Grade: B
Falsy: the string "0" is considered false
Entry granted

Running match_expression.php:

Status 404: Not Found
Temperature 30 is Warm

Running loops.php:

for loop: 1 2 3 4 5 
while loop: 10 8 6 4 2 
do-while loop: run(0) run(1) run(2) 

Running foreach_loop.php:

Language: PHP
Language: Python
Language: Rust
PHP is at version 8.4
Python is at version 3.13
Rust is at version 1.85

Running loop_control.php:

Odd numbers: 1 3 5 7 9 
Searching: 1 2 3 found 4, stopping

Running concise_conditions.php:

Account: Empty or overdrawn
Welcome, Guest
Theme: dark, Language: en

Key Concepts

  • Weak typing affects conditions — PHP coerces condition values to booleans, so 0, "", "0", null, and empty arrays are all falsy. The string "0" being falsy is a classic gotcha.
  • match is the modern switch — It uses strict (===) comparison, returns a value, has no fall-through, and needs no break. Use it instead of switch in PHP 8+.
  • foreach is the workhorse loop — It cleanly iterates both indexed and associative arrays, with optional $key => $value destructuring.
  • continue and break shape loopscontinue skips the current iteration; break exits the loop. Both accept a numeric level for nested loops.
  • ?? vs ?: — The null coalescing operator (??) only triggers on null or undefined values and won’t emit a warning for missing array keys; the Elvis operator (?:) triggers on any falsy value.
  • Choose the right loop — Use for for counted iterations, while for condition-driven loops, do-while when the body must run at least once, and foreach for collections.

Running Today

All examples can be run using Docker:

docker pull php:8.4-cli-alpine
Last updated:

Comments

Loading comments...

Leave a Comment

2000 characters remaining