php language basics

Control Flow

Control flow is how PHP decides which lines run, how many times they run, and when the script should stop doing one thing and move to another. Without control flow, a PHP file would only run from top to bottom once.

You use control flow whenever you validate input, choose a shipping rule, loop over orders, skip invalid rows, stop after finding a match, or show different output for different states. It is one of the first places bugs appear because a condition that looks small can change the whole path through the program.

if, elseif, And else

Use if when code should run only when a condition is true. Use elseif for additional branches, and else for the fallback.

PHP example
<?php

$orderStatus = 'paid';

if ($orderStatus === 'paid') {
    echo "Ship the order\n";
} elseif ($orderStatus === 'pending') {
    echo "Wait for payment\n";
} else {
    echo "Ask support to review\n";
}

// Prints:
// Ship the order

Each branch should represent a real rule. If the words in the condition are unclear, name the condition before the if.

PHP example
<?php

$totalCents = 7200;
$country = 'GB';

$qualifiesForFreeShipping = $totalCents >= 5000 && $country === 'GB';

if ($qualifiesForFreeShipping) {
    echo "Free shipping\n";
}

// Prints:
// Free shipping

The named variable makes the business rule easier to review than a long condition hidden inside the if.

Guard Clauses

A guard clause handles a case early so the main path stays clear. This is common in validation and permission checks.

PHP example
<?php

$quantity = 0;

if ($quantity <= 0) {
    echo "Quantity must be at least 1\n";
    return;
}

echo "Quantity accepted\n";

// Prints:
// Quantity must be at least 1

The return stops the rest of the current file or function from running. Later, inside functions, guard clauses become one of the cleanest ways to reject invalid input before doing useful work.

match For Exact Choices

match is useful when one expression maps to one result. It uses strict comparison and returns a value.

PHP example
<?php

$paymentStatus = 'failed';

$message = match ($paymentStatus) {
    'paid' => 'Ship the order',
    'pending' => 'Wait for payment',
    'failed' => 'Ask the customer to try again',
    default => 'Ask support to review',
};

echo $message . "\n";

// Prints:
// Ask the customer to try again

Use match for clear exact cases. Use if when each branch needs several checks or several statements.

Looping With foreach

foreach is the loop you will use most often with arrays. It runs once for each item.

PHP example
<?php

$orders = [
    ['id' => 101, 'status' => 'paid'],
    ['id' => 102, 'status' => 'pending'],
    ['id' => 103, 'status' => 'paid'],
];

foreach ($orders as $order) {
    if ($order['status'] !== 'paid') {
        continue;
    }

    echo "Ship order {$order['id']}\n";
}

// Prints:
// Ship order 101
// Ship order 103

continue skips the rest of the current loop item and moves to the next one. Here it skips orders that are not paid.

break Stops A Loop

Use break when the loop has found what it needs and should stop.

PHP example
<?php

$emails = [
    'bad-address',
    'admin@example.com',
    'support@example.com',
];

$firstValidEmail = null;

foreach ($emails as $email) {
    if (!str_contains($email, '@')) {
        continue;
    }

    $firstValidEmail = $email;
    break;
}

echo $firstValidEmail . "\n";

// Prints:
// admin@example.com

break is useful for searches. Do not keep looping once the answer is already known.

while And for

Use while when a loop should continue while a condition remains true. Use for when you have a simple counter.

PHP example
<?php

$attemptsRemaining = 3;

while ($attemptsRemaining > 0) {
    echo "Trying request, attempts left: {$attemptsRemaining}\n";
    $attemptsRemaining--;
}

// Prints:
// Trying request, attempts left: 3
// Trying request, attempts left: 2
// Trying request, attempts left: 1

Be careful with while: the condition must eventually become false. Otherwise, the loop can run forever.

PHP example
<?php

for ($page = 1; $page <= 3; $page++) {
    echo "Fetch page {$page}\n";
}

// Prints:
// Fetch page 1
// Fetch page 2
// Fetch page 3

for is good for counters, but foreach is usually clearer when looping over arrays.

Common Mistakes

The most common mistake is writing the condition backwards. Read conditions out loud: "if status is not paid, continue" is easier to check than guessing from symbols alone.

Another common mistake is forgetting the fallback branch. If a status can be paid, pending, failed, or unknown, the code should say what happens when the value is unknown.

Be careful with loops that change the array they are looping over. That can be useful later, but for beginner code it is usually clearer to build a new array or print the result directly.

What You Should Be Able To Do

After this lesson, you should be able to:

  • choose between if, elseif, else, and match;
  • write a guard clause for invalid input;
  • loop over arrays with foreach;
  • use continue to skip one item;
  • use break to stop after finding a result;
  • use while and for for simple repeated work;
  • explain which branch or loop iteration will run before executing the code.

Practice

Task: Ship Paid Orders

Task

Write a PHP script that loops over orders and prints only the orders that are ready to ship.

Use this starting data:

PHP example
<?php

$orders = [
    ['id' => 501, 'status' => 'paid'],
    ['id' => 502, 'status' => 'pending'],
    ['id' => 503, 'status' => 'paid'],
];

Your script should:

  • loop over every order with foreach;
  • skip orders where status is not paid;
  • print Ship order 501 and Ship order 503.

Hints

  • Use !== to check for orders that are not paid.
  • Use continue to skip the current order.
  • Keep the output inside the loop.
Show solution

Solution

PHP example
<?php

$orders = [
    ['id' => 501, 'status' => 'paid'],
    ['id' => 502, 'status' => 'pending'],
    ['id' => 503, 'status' => 'paid'],
];

foreach ($orders as $order) {
    if ($order['status'] !== 'paid') {
        continue;
    }

    echo "Ship order {$order['id']}\n";
}

// Prints:
// Ship order 501
// Ship order 503

Explanation

The foreach loop visits every order. The if condition catches orders that are not paid, and continue skips them. Only paid orders reach the echo line.

Task: Predict Loop Output

Task

Before running this code, predict exactly what it prints.

PHP example
<?php

$codes = ['draft', 'paid', 'cancelled', 'paid'];

foreach ($codes as $code) {
    if ($code === 'draft') {
        continue;
    }

    if ($code === 'cancelled') {
        break;
    }

    echo "Process {$code}\n";
}

Then run the code and compare the real output with your prediction.

Hints

  • continue skips only the current loop item.
  • break stops the whole loop.
  • The second paid value is after cancelled.
Show solution

Solution

PHP example
<?php

$codes = ['draft', 'paid', 'cancelled', 'paid'];

foreach ($codes as $code) {
    if ($code === 'draft') {
        continue;
    }

    if ($code === 'cancelled') {
        break;
    }

    echo "Process {$code}\n";
}

// Prints:
// Process paid

Explanation

The first value is draft, so continue skips it. The next value is paid, so it is printed. The next value is cancelled, so break stops the loop before the final paid value is reached.

Task: Fix Shipping Branch

Task

Fix this shipping message script. It currently checks the broad condition first, so express orders never reach the express branch.

PHP example
<?php

$shippingMethod = 'express';

if ($shippingMethod !== '') {
    echo "Standard shipping\n";
} elseif ($shippingMethod === 'express') {
    echo "Express shipping\n";
} else {
    echo "Choose a shipping method\n";
}

Rewrite the branches so:

  • express prints Express shipping;
  • standard prints Standard shipping;
  • an empty string prints Choose a shipping method;
  • any other value prints Unknown shipping method.

Hints

  • Put the most specific checks before broader checks.
  • Use elseif for the second and third known paths.
  • Keep an else branch for unexpected values.
Show solution

Solution

PHP example
<?php

$shippingMethod = 'express';

if ($shippingMethod === 'express') {
    echo "Express shipping\n";
} elseif ($shippingMethod === 'standard') {
    echo "Standard shipping\n";
} elseif ($shippingMethod === '') {
    echo "Choose a shipping method\n";
} else {
    echo "Unknown shipping method\n";
}

// Prints:
// Express shipping

Explanation

The original code checked $shippingMethod !== '' first. That condition is true for both express and standard, so the more specific express branch could never run.

The fixed version checks exact known values first, then handles the empty value, then keeps a final fallback for unexpected input.