"если" против "переключателя"
Возможный дубликат:
"else if" быстрее, чем "switch() case" ?
В последнее время я столкнулся с множеством ситуаций, когда у меня очень простые условные выражения, и мне нужно отделить поток приложений. "Простейшие" средства для выполнения того, что я делаю, - это просто старая инструкция if
/elseif
:
if($value == "foo") {
// ...
} elseif($value == "bar") {
// ...
} elseif($value == "asdf" || $value == "qwerty") {
// ...
}
... но я также рассматриваю что-то вроде:
switch($value) {
case "foo":
// ...
break;
case "bar":
// ...
break;
case "qwer":
case "asdf":
// ...
}
Это кажется немного менее читаемым, но, возможно, более результативным? Однако, когда в условном выражении все больше и больше выражений, кажется, что оператор switch гораздо читабельнее и полезен:
switch($value) {
case "foo":
// ...
break;
case "bar":
case "baz":
case "sup":
// ...
break;
case "abc":
case "def":
case "ghi":
// ...
break;
case "qwer":
case "asdf":
// ...
}
Я также видел варианты, в которых поток кода разветвлен с использованием массивов и функций:
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();
}
Этот последний вариант также, вероятно, имеет преимущество в том, что он может быть распределен между несколькими файлами, хотя он довольно уродлив.
Что, по вашему мнению, имеет наибольшее преимущество с наименьшими компромиссами с точки зрения производительности, удобочитаемости и простоты использования?
Ответы
Ответ 1
Лично я считаю, что переключатель намного читаем. Вот почему:
if ($foo == 'bar') {
} elseif ($foo == 'baz') {
} elseif ($foo == 'buz') {
} elseif ($fou == 'haz') {
}
Сжатый таким образом, вы можете легко увидеть поездку (будь то опечатка или честная разница). Но с помощью переключателя вы неявно понимаете, что означает:
switch ($foo) {
case 'bar':
break;
case 'baz':
break;
case 'buz':
break;
case 'haz':
break;
}
Плюс, который легче читать:
if ($foo == 'bar' || $foo == 'baz' || $foo == 'bat' || $foo == 'buz') {
}
или
case 'bar':
case 'baz':
case 'bat':
case 'buz':
break;
С точки зрения производительности... Ну, не беспокойтесь о производительности. Если вы не делаете несколько тысяч из них внутри жесткой петли, вы даже не сможете сказать разницу (разница, скорее всего, будет в диапазоне микросекунды, если не ниже).
Перейдите к методу, который вы найдете наиболее читаемым. Это важная часть. Не пытайтесь микро-оптимизировать. Помните, Premature Optimization Is The Root Of All Evil
...
Ответ 2
Я знаю, микро-оптимизация плохая. Но мне любопытно, что я сделал небольшое тестирование, используя этот 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");
Результирующие данные (для числа = 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
Запустили script на моем старом и медленном компьютере Windows с PHP 5.3.1 или 5.3.2, не знаю, знаете ли.
Ответ 3
Вы должны использовать полиморфизм как альтернативу структурам управления, например, if или switch. Это особенно удобно, если у вас очень много опций, так как это может упростить логику управления.
Я написал о концепции здесь: http://codeutopia.net/blog/2009/02/02/avoiding-endless-switch-case-structures-with-classes/
Ответ 4
Переключатель сообщает более поздним читателям, что вы разветвляетесь на основе значения одного значения, которое они должны были бы подразумевать иначе, просматривая все условия. Поэтому я предпочел бы переключатель для ясности