note 98225 added to control-structures.switch
| From: | theimp at iinet dot net dot au | Date: | Wed, 02 Jun 2010 20:04:44 +0000 |
| Subject: | note 98225 added to control-structures.switch | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-169831@lists.php.net to get a copy of this message | ||
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() !
Consider the following:
<?php
function flavor($type = null)
{
switch ($type) {
/* Note the isolation of break; statements and the fact that default: is at the top */
default:
$type = null;
case $array[] = "chocolate":
if ($type != null) {
$array = array($type);
break;
}
case $array[] = "strawberry":
if ($type != null) {
$array = array($type);
break;
}
case $array[] = "vanilla":
if ($type != null) {
$array = array($type);
break;
}
}
if ( (count($array) != 1) ) {
return "Flavors available: " . implode(", ", $array);
} else {
return "Flavor selected: " . implode(", ", $array);
}
}
echo flavor() . "<br>";
/* Flavors available: chocolate, strawberry, vanilla */
echo flavor("banana") . "<br>";
/* Flavors available: chocolate, strawberry, vanilla */
echo flavor("chocolate") . "<br>";
/* Flavor selected: chocolate */
?>
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.
----
Server IP: 117.55.229.1
Probable Submitter: 203.59.75.251
----
Manual Page -- http://www.php.net/manual/en/control-structures.switch.php
Edit -- https://master.php.net/note/edit/98225
Del: integrated -- https://master.php.net/note/delete/98225/integrated
Del: useless -- https://master.php.net/note/delete/98225/useless
Del: bad code -- https://master.php.net/note/delete/98225/bad+code
Del: spam -- https://master.php.net/note/delete/98225/spam
Del: non-english -- https://master.php.net/note/delete/98225/non-english
Del: in docs -- https://master.php.net/note/delete/98225/in+docs
Del: other reasons-- https://master.php.net/note/delete/98225
Reject -- https://master.php.net/note/reject/98225
Search -- https://master.php.net/manage/user-notes.php