switch

(PHP 4, PHP 5, PHP 7)

The switch statement is similar to a series of
IF statements on the same expression. In many occasions, you may
want to compare the same variable (or expression) with many
different values, and execute a different piece of code depending
on which value it equals to. This is exactly what the
switch statement is for.

Note:
Note that unlike some other languages, the
continue statement
applies to switch and acts similar to break. If you
have a switch inside a loop and wish to continue to the next iteration of
the outer loop, use continue 2.

It is important to understand how the switch
statement is executed in order to avoid mistakes. The
switch statement executes line by line
(actually, statement by statement). In the beginning, no code is
executed. Only when a case statement is found
whose expression evaluates to a value that matches the value of the
switch expression does PHP begin to execute the
statements. PHP continues to execute the statements until the end
of the switch block, or the first time it sees
a break statement. If you don't write a
break statement at the end of a case's
statement list, PHP will go on executing the statements of the
following case. For example:

Here, if $i is equal to 0, PHP would execute all of the echo
statements! If $i is equal to 1, PHP would execute the last two
echo statements. You would get the expected behavior ('i equals 2'
would be displayed) only if $i is equal to 2. Thus,
it is important not to forget break statements
(even though you may want to avoid supplying them on purpose under
certain circumstances).

In a switch statement, the condition is
evaluated only once and the result is compared to each
case statement. In an elseif
statement, the condition is evaluated again. If your condition is
more complicated than a simple compare and/or is in a tight loop,
a switch may be faster.

The statement list for a case can also be empty, which simply
passes control into the statement list for the next case.

User Contributed Notes 53 notes

This is listed in the documentation above, but it's a bit tucked away between the paragraphs. The difference between a series of if statements and the switch statement is that the expression you're comparing with, is evaluated only once in a switch statement. I think this fact needs a little bit more attention, so here's an example:

Just so others know whom may not, that's because PHP does automatic type conversion if a string is evaluated as an integer (it sees the 2 in '2string' so when compared like if ('2string' == 2), PHP sees if (2 == 2) ).

Something not mentioned in the documentation itself, and only touched on momentarily in these notes, is that the default: case need not be the last clause in the switch.<?phpfor($i=0; $i<8; ++$i){ echo $i,"\t"; switch($i) { case 1: echo "One"; break; case 2: default: echo "Thingy"; break; case 3: case 4: echo "Three or Four"; break; case 5: echo "Five"; break; } echo "\n";}?>Outputs what you'd expect, namely0 Thingy1 One2 Thingy3 Three or Four4 Three or Four5 Five6 Thingy7 Thingywith case 2 and the default both producing the same result ("Thingy"); strictly speaking, the case 2 clause is completely empty and control just falls straight through. The same result could have been achieved with<?phpswitch($i){ case 1: echo "One"; break; case 3: case 4: echo "Three or Four"; break; case 5: echo "Five"; break; default: echo "Thingy"; break;}?>But if "case 2" represented a fairly common case (other than "everything else"), then it would be better to declare it explicitly, not only because it saves time by not having to test EVERY other case first (in the current example, PHP finds 'case 2' in the first switch in two tests, but in the second switch it has to make four tests before giving up and going with the default) but also because someone (perhaps yourself in a few months' time) will be reading the code and expecting to see it handled. Listing it explicitly aids comprehension

Be careful if distinguishing between NULL and (int)0. As implied in the above documentation, the case statements are equivalent to the '==' operator, not the '===' operator, so the following code did not work as i expected:

Instead, I may use a chain of else-ifs. (On this page, kriek at jonkreik dot com states that "in most cases [a switch statement] is 15% faster [than an else-if chain]" but jemore at m6net dotdot fr claims that when using ===, if/elseif/elseif can be 2 times faster than a switch().)

Alternatively, if i prefer the appearance of the switch() statement I may use a trick like the one nospam at please dot com presents:

'continue' ends the switch, not the case, just as it would with any other flow control. Think of it as putting the execution pointer right before the ending accolade (that is, the }) because that is essentially what happens. In the case of a for loop, this would cause the iteration clause to execute, and if applicable, the loop to begin again. However, switches do not loop, which is why (as noted above, in the manual!) a continue statement essentially acts as a break when within a switch.

Using this type of range randomizer is useful for game development and it can be useful on the web too, for things where you don't want to use a randomizer just for things like (1-5) where you wanted a more then likely result for one thing over another. The switch statement saves from writing spaghetti code if statements.

In reply to earlier comment, "switch"- I found this to be one of the best ways to interpret 'actions'. Simply create a new instance of Handler_action before including any content source files. This is a highly stripped version of the class.

The real one I created handles (and secures) input for $_GET and $_POST, creates a 'permission' array that only allows certain actions to be called by non-admins, and creates handy little diagnostic messages that can be displayed upon redirecting.

Did you know that switch() and case() can also accomodate things like basic math calculations and counter incrementing? They do. In this example, I use a switch statement (which is inside of a while loop) to alternate the background color of a table row. It gives me a cool spool-printer-paper effect.

As you can see, I increment $ctr by 1 in the switch() itself, and the final case() does a simple calculation. Simple, but powerful. [Remember, the above example is inside of a while() loop... each time it iterates, switch increments $ctr.]

It's easy to abuse the switch syntax to do some very useful things. As this example will show, the possibilities can go beyond even Duff's Device-style craziness (not that this example is nearly as clever as Duff's Device, but it demonstrates how you can do certain things other than simply the increment/decrement/assignment that's possible in C).

Fundamentally, this works mostly due to the fact that, from the point of view of the assembler/interpreter, a switch block is hardly any different from a bunch of GOTO labels and if() evaluations. But, like an if() evaluation, the line of a case: statement is evaluated as an expression. So, in this case, we can perform an assignment and match the result of that assignment, because the return value of an assignment is the data that was assigned (and not the value of the variable it was assigned to, as you might expect).

So far, this is not actually amazing, even if it is a bit unintuitive. From a language point-of-view, it would be the same as an if($var = "string") statement which is using an assignment (=) rather than a comparison (==) operator. When you look at the pre-processing optimization, because a normal assignment of $var = "string" will always equal "string", it makes sense to have the result of that expression simply be equal to the right side of the expression (the right side is used rather than the left to let the assembler/interpreter work faster, on account of how they traditionally simply change the memory location for the assigned variable rather than copy the memory around unnecessarily).

Where this becomes more interesting is where, in PHP, you have language constructs that behave like functions but are used like statements. An $array[] = "string" expression is actually a language construct that just happens to behave a lot like a function, but you use it in the same way that you use an assignment expression, and like an expression, it always evaluates to the right side of the expression; in this case, "string" and not array() .

The assembler/interpreter can't use the right side of the expression as a shortcut for the result of a function, so you can't use functions in this way in a case statement. You also can't get around this limit on calling functions from the case line by using variable functions, because they are used in the same way as functions.

But imagine what you could do with other language constructs, like eval() or include() !

What makes this example useful is that you don't need a variable somewhere that contains the available options (even within the function itself), so to support new options, you only ever have to change the code to add the new option - you don't need to update some variable somewhere that controls whether or not it works or whether or not people can tell that there's a new option.

very useful if you want your cases to be presented in a logical order in the code (as in, not saying case 1, case 3, case 2/default) and your cases are very long so you do not want to repeat the entire case code at the bottom for the default

The reason for this as mentioned on http://uk3.php.net/ternary is that: "If you compare an integer with a string, the string is converted to a number. If you compare two numerical strings, they are compared as integers. These rules also apply to the switch statement." Effectively it's saying if ($a=="first") which becomes does ($a (0) == 0) which is yes.

In my example this mean't a date had a regular expression of an email applied to it which didnt help!

In answer to njones at fredesign dot com, what you're seeing is the way the switch statement is supposed to work. The switch statement evaluates the cases, top to bottom, until it finds the first one that matches the value being switch()ed on. So, for example, if you had:

Only "Two" would get echoed. "Two again" would NOT get echoed, because once the first case matches, the rest of them do NOT get evaluated. As soon as a matching case is found, the statements starting at that case get executed until the first break, then control flows out the bottom of the switch block.

Be very careful when you're using text strings as cases. If the variable supplied to switch() is an integer, the cases would be converted to integer before the comparison is made (usually to zero). The following snippet prints "hello".

Regarding [php_net at mcdragonsoftware dot com 17-Jun-2011 09:53]; the elegant function and syntax provided for an "inline switch" statement is more readable and about 25% faster than this alternative (that uses existing builtin functions), which produces the same result:

Haven't seen it mentioned here, but at least in my version (PHP 5.2.5) and I'm sure all of PHP 5, the switch statement is a great way to check type safe enumerates that are otherwise missing in the PHP language. Example:

Sometimes you need to execute a common piece of code for several cases, and then execute some special code for each of those cases in particular. You'd then be tempted to duplicate "case" entries, like so:

<?php

$health = 50;$prevActionType = "none";

$action = "kill";

switch($action) {

case "heal":$prevActionType = "good";$health += 10; break;

case "hurt":case "kill":$prevActionType = "bad"; break;

case "hurt":$health -= 10; break;

case "kill":$health = 0; break;

}

?>

That won't work as intended -- you'll enter at the first case that matches ($prevActionType = "bad") and then exit the switch altogether.

I did some benchmarking.The array system is faster than the switch system.

Here were my average time results of 1000 itterations of assigning the numeric value to the month.The value was randomized between each itteration (this was not added to the benchmark value), so each method was simulated with various data to stress different points.

a string is 0switch string test without explicit cast:0 is a string (this is not what we want to see)switch string test with explicit cast: default :0 is something else (this is the correct choice)a string is TRUESwitch boolean test without explicit cast:1 is a string (this is not what we want to see)Switch boolean test with explicit cast: default:s 1 is something else (this is the correct choice)

often you will have to perform multiple actions in sequence, but this sequence must be broken once one of them detects a stop condition (such as an error, when validating form request variables).
One way is to use:

if (check1()
&& check2()
&& check3()
) valid();
else error();

But when the sequence is long and must reordered, this can be errorprone because not all line of check have the same syntax (imagine that you want to comment one of them).

Another way is to rewrite it as:

check1() and
check2() and
check3() and
...
valid() or
error();

The above syntax does not fit well when the valid() code must be several statements.
An alternative syntax can be:

This last equivalent sample show you that each case expressions is evaluated, until one of them evaluates to a value equal (==) to the switch expression. Above, the error() code will only be called if one of the check evaluates to false. And the valid() code will only be evaluated only if the switch reach the default, which means that none of the above check returned false...

Regarding bishop's comment below, although using: switch($bug === 0 ? '' : $bug) {may work, ( and although I do like the ternary operator, :) it might be more intuitive/readable to use this instead: switch( (string)$bug ) { which typecasts the variable to a string to ensure that "0" will be handled correctly.

It's has already been mentioned indirectly in a few posts, but it is important to realize that switch statements evaluate each case with the "==" operator by default. This can lead to unexpected results when comparing strings to integers, because PHP will convert the string to an integer. In many cases this means a string can be equivalent to the integer 0.

The result will be an "a" echoed out. What PHP does in this instance, is once it realizes that it's attempting to compare string ("a") to an integer (0), it converts "a" into an integer which ends up satisfying the first case.

Also note that even though a conditional statement needs to be explicitly set in each case to gain expected behavior, the switch can still execute faster then an "ifelse" block because PHP will not continue to evaluate conditions once a case has been satisfied.

So now the case expression contains an if statement in simplified notation which either returns the value of $x if the expression is true (so the case matches) or false, if the expression was false (so the case does not match).Be aware that it only works if $x never actually is "false" because then it would match in either case. So the "false" in the above code should always be any random value which is not a possible value for $x.