Possible Duplicate:
is “else if” faster than “switch() case” ?
I've encountered a lot of situations lately where I have very simple conditionals and need to branch application flow. The "simplest" means of accomplishing what I'm doing is just a plain old if
/elseif
statement:
if($value == "foo") {
// ...
} elseif($value == "bar") {
// ...
} elseif($value == "asdf" || $value == "qwerty") {
// ...
}
...but I'm also considering something like:
switch($value) {
case "foo":
// ...
break;
case "bar":
// ...
break;
case "qwer":
case "asdf":
// ...
}
This seems a little less readable, but perhaps it's more performant? However, when there are more and more "or" expressions in the conditional, it seems that the switch statement is much more readable and useful:
switch($value) {
case "foo":
// ...
break;
case "bar":
case "baz":
case "sup":
// ...
break;
case "abc":
case "def":
case "ghi":
// ...
break;
case "qwer":
case "asdf":
// ...
}
I've also seen options where code flow is branched using arrays and functions:
function branch_xyz() {/* ... */}
function branch_abc() {/* ... */}
function branch_def() {/* ... */}
$branches = array(
"xyz"=>"branch_xyz",
"abc"=>"branch_abc",
"def"=>"branch_def"
);
if(isset($branches[$value])) {
$fname = $branches[$value];
$fname();
}
This last option also presumably has the benefit of being distributable across multiple files, though it is pretty ugly.
Which do you feel has the most advantages with the fewest tradeoffs in terms of performance, readability, and ease of use?
Personally, I find the switch a lot more readable. Here's the reason:
if ($foo == 'bar') {
} elseif ($foo == 'baz') {
} elseif ($foo == 'buz') {
} elseif ($fou == 'haz') {
}
Condensed like that, you can easily see the trip up (be it a typo, or a honest difference). But with a switch, you know implicitly what was meant:
switch ($foo) {
case 'bar':
break;
case 'baz':
break;
case 'buz':
break;
case 'haz':
break;
}
Plus, which is easier to read:
if ($foo == 'bar' || $foo == 'baz' || $foo == 'bat' || $foo == 'buz') {
}
or
case 'bar':
case 'baz':
case 'bat':
case 'buz':
break;
From a performance standpoint... Well, don't worry about the performance. Unless you're doing a few thousand of them inside of a tight loop, you won't even be able to tell the difference (the difference will likely be in the micro-second range, if not lower).
Go for the method that you find the most readable. That's the important part. Don't try to micro-optimize. Remember, Premature Optimization Is The Root Of All Evil
...
I know, micro-optimization is bad. But curious as I am, I did a little benchmark using this script:
<?php
$numof = 100000;
$file = fopen('benchmark.php', 'w');
if (!$file) die('file error');
fwrite($file, '<pre><?php' . "\n" . 'echo $i = $_GET[\'i\'], "\n";' . "\n");
fwrite($file,
'$start = microtime(true);
if ($i == 0) {}' . "\n");
for ($i = 1; $i < $numof; ++$i) {
fwrite($file, 'elseif($i == '.$i.') {}'. "\n");
}
fwrite($file,
'echo \'elseif took: \', microtime(true) - $start, "\n";' . "\n");
fwrite($file,
'$start = microtime(true);
switch($i) {' . "\n");
for ($i = 1; $i < $numof; ++$i) {
fwrite($file, 'case '.$i.': break;'. "\n");
}
fwrite($file,
'}
echo \'switch took: \', microtime(true) - $start, "\n";' . "\n");
Resulting data (for numof = 100000):
i: 0
elseif took: 6.2942504882812E-5
switch took: 3.504753112793E-5
i: 10
elseif took: 6.4849853515625E-5
switch took: 4.3869018554688E-5
i: 100
elseif took: 0.00014805793762207
switch took: 0.00011801719665527
i: 1000
elseif took: 0.00069785118103027
switch took: 0.00098896026611328
i: 10000
elseif took: 0.0059938430786133
switch took: 0.0074150562286377
i: 100000 (first non-existing offset)
elseif took: 0.043318033218384
switch took: 0.075783014297485
Have run the script on my old and slow windows machine with PHP 5.3.1 or 5.3.2, dunno right know.
You should consider using polymorphism as an alternative to control structures like if or switch. It's especially convenient if you have very many options, as it can simplify the control logic a lot.
I wrote about the concept here: http://codeutopia.net/blog/2009/02/02/avoiding-endless-switch-case-structures-with-classes/
Switch tells later readers that you're branching based on the value of a single value, which they would have to imply otherwise by looking at all the conditions. So I'd prefer the switch for clarity