PHP Switch

JA JASWANT Updated 16 Oct 2026
8 min read ·Lesson 2 of 3

What Is the switch Statement?

In simple terms: switch compares one value against a list of possible values and runs the code for the one that matches. It is an organized alternative to a long chain of if...elseif statements that all test the same variable.

Technically: switch evaluates an expression once, then compares the result with each case value using loose comparison (==). Execution starts at the first matching case and continues until a break statement (or the end of the switch) is reached.

Why It Exists

Code like this repeats the same variable in every condition:

if ($status === 'pending') { ... }
elseif ($status === 'paid') { ... }
elseif ($status === 'shipped') { ... }
elseif ($status === 'delivered') { ... }
else { ... }

switch names the value once and lists the possible cases, which is easier to scan when there are many options.


Syntax

switch (expression) {
    case value1:
        // code for value1
        break;
    case value2:
        // code for value2
        break;
    default:
        // code when no case matches
}
PartMeaning
switch (expression)The value to compare, evaluated once
case value:A value to compare against; execution starts here when it matches
break;Leaves the switch
default:Runs when no case matches (optional)

Example

<?php
$status = 'shipped';

switch ($status) {
    case 'pending':
        echo "Awaiting payment\n";
        break;
    case 'paid':
        echo "Payment received, preparing your order\n";
        break;
    case 'shipped':
        echo "Your order is on the way\n";
        break;
    case 'delivered':
        echo "Delivered. Enjoy your purchase!\n";
        break;
    default:
        echo "Unknown order status\n";
}

Output

Your order is on the way

How It Works

  1. $status is evaluated once: 'shipped'.
  2. PHP compares it with each case value from top to bottom: 'pending', 'paid', then 'shipped', which matches.
  3. Execution starts at case 'shipped': and runs its statements.
  4. break ends the switch, so the remaining cases are not executed.
  5. If no case had matched, the default block would run.

The Role of break: Fall-Through

What Happens Without break

case labels only mark where execution starts. Without a break, PHP continues running the statements of the following cases — this is called fall-through.

<?php
$status = 'pending';

switch ($status) {
    case 'pending':
        echo "Awaiting payment\n";
    case 'paid':
        echo "Payment received\n";
        break;
    case 'shipped':
        echo "On the way\n";
        break;
}

Output

Awaiting payment
Payment received

The pending case is missing its break, so execution "falls through" into the paid case and prints a message that is wrong for a pending order. Forgetting break is the most common switch bug.

Intentional Fall-Through: Grouping Cases

Fall-through is useful when several values should run the same code. Stack the case labels without statements between them:

<?php
function dayType(string $day): string
{
    switch ($day) {
        case 'Sat':
        case 'Sun':
            return 'Weekend';
        case 'Fri':
            return 'Almost the weekend';
        default:
            return 'Weekday';
    }
}

foreach (['Mon', 'Fri', 'Sun'] as $day) {
    echo "$day: " . dayType($day) . "\n";
}

Output

Mon: Weekday
Fri: Almost the weekend
Sun: Weekend
  • 'Sat' and 'Sun' share one block.
  • Inside a function, return leaves both the switch and the function, so no break is needed after it.

When fall-through is intentional in a case that does contain statements, add a comment such as // no break so readers know it is deliberate.


The default Case

  • default runs when no case matches.
  • It is optional, but including it is recommended — it handles unexpected values explicitly instead of silently doing nothing.
  • It can appear anywhere in the list, but it is conventionally placed last.
  • A switch can have only one default.
<?php
$paymentMethod = 'crypto';

switch ($paymentMethod) {
    case 'card':
    case 'upi':
    case 'netbanking':
        echo "Redirecting to payment gateway...\n";
        break;
    case 'cod':
        echo "Cash on delivery selected\n";
        break;
    default:
        echo "Payment method '$paymentMethod' is not supported\n";
}

Output

Payment method 'crypto' is not supported

switch Uses Loose Comparison

switch compares with ==, so type juggling applies (see PHP Type Juggling):

<?php
$input = '1e1';

switch ($input) {
    case '10':
        echo "Matched '10'\n";
        break;
    default:
        echo "No match\n";
}

$flag = '0';

switch ($flag) {
    case false:
        echo "Matched false\n";
        break;
    case '0':
        echo "Matched '0'\n";
        break;
}

Output

Matched '10'
Matched false
  • '1e1' == '10' is true because both strings are numeric and equal to 10.
  • '0' == false is true, so the first matching case is false, not '0'.

For exact matching, normalize the value's type before the switch (for example, cast to int or compare only strings), or use match, which compares strictly.


switch (true) for Range Conditions

A case can contain any expression. Switching on true runs the first case whose expression is true:

<?php
$score = 82;

switch (true) {
    case $score >= 90:
        $grade = 'A';
        break;
    case $score >= 75:
        $grade = 'B';
        break;
    case $score >= 60:
        $grade = 'C';
        break;
    default:
        $grade = 'F';
}

echo "Grade: $grade\n";

Output

Grade: B

This works, but if...elseif or match (true) expresses range checks more directly. You will see switch (true) in older code.


Multiple Statements in a Case

Each case can contain as many statements as needed, which is one advantage switch has over match:

<?php
function handleCommand(string $command, array &$cart): string
{
    switch ($command) {
        case 'add':
            $cart[] = 'item-' . (count($cart) + 1);
            $message = 'Item added';
            break;

        case 'remove':
            if ($cart === []) {
                return 'Cart is already empty';
            }
            array_pop($cart);
            $message = 'Item removed';
            break;

        case 'clear':
            $cart = [];
            $message = 'Cart cleared';
            break;

        default:
            return "Unknown command: $command";
    }

    return "$message. Cart has " . count($cart) . " item(s).";
}

$cart = [];

foreach (['add', 'add', 'remove', 'checkout', 'clear', 'remove'] as $command) {
    echo handleCommand($command, $cart) . "\n";
}

Output

Item added. Cart has 1 item(s).
Item added. Cart has 2 item(s).
Item removed. Cart has 1 item(s).
Unknown command: checkout
Cart cleared. Cart has 0 item(s).
Cart is already empty

How It Works

  • array &$cart passes the cart by reference, so the function can modify the caller's array (see Pass by Reference).
  • Each case updates the cart, sets a message, and breaks to the shared return at the end.
  • The remove case contains its own if, showing that cases can hold any logic.
  • Unknown commands and the empty-cart situation return early.

switch Inside Loops: break and continue

Inside a switch, break exits the switch, not the surrounding loop. To exit the loop from inside a switch, use break 2; to skip to the next loop iteration, use continue 2.

<?php
$lines = ['INFO start', 'SKIP debug', 'ERROR disk full', 'INFO end'];

foreach ($lines as $line) {
    $level = strtok($line, ' ');

    switch ($level) {
        case 'SKIP':
            continue 2;          // next line in the foreach
        case 'ERROR':
            echo "Stopping: $line\n";
            break 2;             // leave the foreach completely
        default:
            echo "Logged: $line\n";
    }

    echo "  (processed)\n";
}

Output

Logged: INFO start
  (processed)
Stopping: ERROR disk full

How It Works

  • strtok($line, ' ') returns the first word of the line.
  • continue 2 skips the rest of the current foreach iteration, so (processed) is not printed for the SKIP line.
  • break 2 exits both the switch and the foreach, so INFO end is never processed.

A plain continue inside a switch behaves like break (it targets the switch), and since PHP 7.3 PHP warns about it at compile time: "continue" targeting switch is equivalent to "break". Use continue 2 when you mean the loop.


switch vs if...elseif vs match

Featureif...elseifswitchmatch (PHP 8.0+)
ComparesAny conditionsOne value against casesOne value against arms
ComparisonWhatever you writeLoose (==)Strict (===)
Fall-throughNoYes, unless breakNo
Returns a valueNoNoYes
Multiple statements per branchYesYesNo (one expression per arm)
No matchNothing happens (unless else)Nothing happens (unless default)Throws UnhandledMatchError

Guidelines:

  • Use match when you are choosing a value based on one input and want strict, safe comparison.
  • Use switch when each case must run several statements, or when you maintain code that already uses it.
  • Use if...elseif for unrelated conditions or complex ranges.

Same Logic With match

<?php
function fileCategory(string $filename): string
{
    return match (strtolower(pathinfo($filename, PATHINFO_EXTENSION))) {
        'jpg', 'jpeg', 'png', 'webp' => 'Image',
        'pdf' => 'PDF document',
        'doc', 'docx' => 'Word document',
        'zip', 'rar' => 'Archive',
        default => 'Other',
    };
}

foreach (['photo.JPG', 'resume.pdf', 'notes.docx', 'backup.zip', 'script.php'] as $file) {
    echo "$file: " . fileCategory($file) . "\n";
}

Output

photo.JPG: Image
resume.pdf: PDF document
notes.docx: Word document
backup.zip: Archive
script.php: Other

The equivalent switch would need a case line per extension, a break after each group, and a variable to hold the result. match lists several values per arm with commas and returns the result directly.


Common Mistakes

Forgetting break

Effect: Execution falls through into the next case.

Fix: End every case with break (or return inside functions), and comment any intentional fall-through.

Relying on Loose Comparison

Effect: '0' matches case false; numeric strings match unexpected cases.

Fix: Normalize types first, or use match.

Using continue Instead of continue 2 in Loops

Effect: continue acts like break for the switch; the rest of the loop body still runs.

Fix: continue 2 (or break 2 to leave the loop).

Omitting default

Effect: Unexpected values are silently ignored, and variables assigned in the cases may remain undefined.

Fix: Always include default, even if it only logs or throws an error.

Duplicate Case Values

Effect: Only the first matching case runs; the duplicate is unreachable.

Fix: Keep case values unique.


Best Practices

  • End every case with break or return, and comment intentional fall-through.
  • Group cases that share behavior by stacking case labels.
  • Always include a default branch.
  • Normalize the switch value's type to avoid loose-comparison surprises.
  • Prefer match for value selection in PHP 8 code; use switch when cases need multiple statements.

Official reference: https://www.php.net/manual/en/control-structures.switch.php

0 Comments

Reviewed before they appear

No comments yet.

PHP
Ask about this post
AI Ask about this post

Ask questions about PHP Switch and get answers drawn from it.

Signed-in readers only.