๐Ÿ“ Web Development

PHP switch: Cleaner Branching Than if else

Sep 11, 20265 min read1 viewsBy Flow

You have five choices to test and the same variable in every test. Written with if else that becomes a ladder of elseif lines where only one word changes on each rung, and the eye slides off it. A PHP switch says the variable once at the top and then lists the values underneath, which is why it reads better and why almost every codebase has some.

It also has one behaviour that catches everybody at least once: a case does not stop at the next case. It keeps going. That is not a bug, it is the feature the whole statement is built on, and once you see why, the missing break stops being mysterious.

The shape of a PHP switch

The variable goes in the brackets, each value you want to match goes after case, and default catches everything you did not list. The colon after each value is not optional.

<?php
$role = 'editor';

switch ($role) {
    case 'admin':
        echo "Full access";
        break;
    case 'editor':
        echo "Can write and publish";
        break;
    case 'author':
        echo "Can write only";
        break;
    default:
        echo "Read only";
}

Output:

php switch output showing the editor case matched and Can write and publish printed

default is optional and does not have to sit last, though putting it anywhere else confuses readers for no gain. If nothing matches and there is no default, the whole statement does nothing at all โ€” no error, no warning, just silence. That silence is worth remembering when a switch appears to be ignored.

What break actually does

Here is the part that surprises people. PHP does not treat each case as a separate box. It finds the first matching case and then runs every line after it, straight through the cases below, until it hits a break or reaches the closing brace. The cases are entry points, not compartments.

Delete the breaks from the example above and watch it run past the match:

<?php
$role = 'editor';

switch ($role) {
    case 'admin':
        echo "Full access\n";
    case 'editor':
        echo "Can write and publish\n";
    case 'author':
        echo "Can write only\n";
    default:
        echo "Read only\n";
}

Output:

php switch output showing fallthrough printing three lines after the editor case matched

It matched editor, printed that line, and then carried on into author and default as well. Nothing above the match ran, because the match is where execution enters. This is called fallthrough, and it explains every "my PHP switch runs the wrong branch" question ever asked.

Grouping cases on purpose

Once fallthrough makes sense it becomes useful. Stack several case lines with no code between them and they all lead to the same block, which is the cleanest way to say "any of these".

<?php
$day = 'Sat';

switch ($day) {
    case 'Sat':
    case 'Sun':
        echo "Weekend";
        break;
    case 'Mon':
    case 'Tue':
    case 'Wed':
    case 'Thu':
    case 'Fri':
        echo "Weekday";
        break;
    default:
        echo "Not a day";
}

Output:

php switch output showing Sat and Sun grouped into one weekend branch

Written as an if else that condition would be $day === 'Sat' || $day === 'Sun', repeating the variable each time. Stacked cases say it once. When a reviewer sees a case with no body and no break, that is deliberate; when they see a case with a body and no break, it usually is not.

A PHP switch compares loosely

This is the trap that costs real time. A switch uses ==, not ===. It does not check the type, only the value after PHP has tried to make the two comparable. So the string "1" matches the number 1, and "1" also matches true.

<?php
$id = "1";

switch ($id) {
    case 1:
        echo "matched the number 1\n";
        break;
    case "1":
        echo "matched the string 1\n";
        break;
}

var_dump($id == 1);   // true  โ€” this is what switch uses
var_dump($id === 1);  // false โ€” this is what you probably meant

Output:

php switch output showing the string 1 matching the numeric case before the string case

The numeric case wins because it is listed first, and the string case is unreachable. If your values can be a mix of numbers and numeric strings, a PHP switch cannot tell them apart.

Worth knowing which PHP you are on here. Before PHP 8.0, comparing a number with a non-numeric string converted the string to a number, so 0 == "hello" was true and a switch (0) would match case "hello". PHP 8.0 reversed that rule: the number is now converted to a string instead, so 0 == "hello" is false. Old tutorials that warn about this are describing PHP 7 behaviour.

match, the strict cousin from PHP 8

PHP 8.0 added match, which fixes the two things a PHP switch gets wrong. It compares with ===, and it is an expression, so it returns a value you can assign instead of echoing from inside each branch.

<?php
$id = "1";

$label = match ($id) {
    1     => "the number one",
    "1"   => "the string one",
    2, 3  => "two or three",
    default => "something else",
};

echo $label;

Output:

php switch alternative match expression output showing the string one matched strictly

Now "1" reaches the string arm, because match checks the type too. There is no fallthrough and no break โ€” each arm is one value or a comma-separated list. One sharp edge: if nothing matches and there is no default, match throws an UnhandledMatchError rather than doing nothing quietly. That is usually what you want, but it means an unhandled value crashes the page instead of skipping it.

Use match when you are picking a value, and a PHP switch when a branch does real work across several statements.

Three mistakes with a PHP switch

The forgotten break. The branch runs, and so does every branch below it. The giveaway is output that is correct but has extra lines glued to the end of it. If you scan a switch and see bodies without breaks, that is the first thing to check โ€” not the condition.

Assuming it compares strictly. A form field is always a string, so $_POST['qty'] is "0", not 0. Feed that to a PHP switch with numeric cases and it will match on value alone. If the type matters, use match, or cast the value before the switch so at least you chose the type deliberately.

Using it where an array would read better. A switch whose every branch does nothing but assign a value is a lookup table written the long way. $labels = ['admin' => 'Full access', 'editor' => 'Can write']; then $labels[$role] ?? 'Read only' is one line, and adding a role means adding one entry rather than three.

Common questions about a PHP switch

What happens if I forget break in a PHP switch?

Execution continues into the cases below the one that matched, running their code as well, until it meets a break or the end of the statement. It is not an error and PHP will not warn you, so the symptom is extra output rather than a crash.

Can a PHP switch use ranges or conditions?

Not directly โ€” each case takes a single value, so you cannot write case > 100. The usual workaround is switch (true) with a real condition in each case, which works because each condition evaluates to true or false and is then compared against true. It is clever, and it is also harder to read than the if else it replaced, so reach for it sparingly.

Is a PHP switch faster than if else?

Not meaningfully. Both walk the branches in order until one matches. Choose whichever expresses the intent more clearly; if you are comparing one variable against a list of fixed values, that is a switch, and if you are testing several unrelated conditions, that is an if else.

What is the difference between switch and match?

match compares with ===, returns a value, has no fallthrough, and throws if nothing matches. A PHP switch compares with ==, returns nothing, falls through without break, and stays silent when nothing matches. match needs PHP 8.0 or newer.

Can I use a PHP switch on a string?

Yes, and it is the most common use. Just remember the loose comparison: a numeric string such as "10" will match a numeric case 10, so keep the types in your cases consistent.

What is next

Branching decides which block runs once. The next step is running a block over and over until a condition changes, which is what PHP loops are for โ€” while, for and foreach, plus the break keyword you have just met doing a slightly different job.

Comments

Loading comments...

Link copied to clipboard