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:
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:
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:
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:
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.
Loading comments...