Возможный дубликат:
«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(); }
Этот последний вариант также, по-видимому, имеет преимущество в том, что он может быть распределен между несколькими файлами, хотя он довольно уродлив.
Что, по вашему мнению, имеет наибольшие преимущества с наименьшими компромиссами с точки зрения производительности, удобочитаемости и простоты использования?
Лично я считаю, что коммутатор намного читабельнее. Вот причина:
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
…
Я знаю, микро-оптимизация плохая. Но, как ни странно, я сделал небольшой тест, используя этот скрипт:
<?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
Запустили сценарий на моем старом и медленном компьютере с Windows с PHP 5.3.1 или 5.3.2, не знаю, знаете ли вы.
Вы должны рассмотреть возможность использования полиморфизма в качестве альтернативы управляющим структурам типа if или switch. Это особенно удобно, если у вас очень много опций, так как это может упростить логику управления.
Я написал о концепции здесь: http://codeutopia.net/blog/2009/02/02/avoiding-endless-switch-case-structures-with-classes/
Переключатель сообщает более поздним читателям, что вы разветвляетесь на основе значения одного значения, которое они должны были бы подразумевать иначе, просматривая все условия. Поэтому я предпочел бы переключатель для ясности