если по сравнению с переключателем

Возможный дубликат:
иначе, если быстрее, чем switch () case?

В последнее время я сталкивался с множеством ситуаций, когда у меня были очень простые условные выражения и мне нужно было разветвлять поток приложения. «Самый простой» способ выполнить то, что я делаю, - это просто старый добрый _1 _ / _ 2_ оператор:

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();
}

Этот последний вариант также, по-видимому, имеет то преимущество, что его можно распространять по нескольким файлам, хотя он довольно уродлив.

Как вы думаете, какое из них имеет наибольшие преимущества с наименьшим количеством компромиссов с точки зрения производительности, удобочитаемости и простоты использования?


person mattbasta    schedule 03.08.2010    source источник
comment
Использование switch лучше в той ситуации, которую вы указали.   -  person Sarfraz    schedule 03.08.2010
comment
Производительность на это даже не влияет. Сначала напишите читаемый код, затем профилируйте и оптимизируйте, где это необходимо.   -  person Frank Farmer    schedule 03.08.2010
comment
Дубликат дубликата и т.п. перспектива "> stackoverflow.com/questions/3387758/   -  person Dave McClelland    schedule 03.08.2010
comment
Возможно, вы захотите ознакомиться с шаблонами поведения GOF.   -  person Gordon    schedule 03.08.2010
comment
@Dave и @STW: Я ищу ответ о удобочитаемости и целесообразности использования, а не о производительности.   -  person mattbasta    schedule 04.08.2010
comment
Ненавистники @stereofrog возненавидят.   -  person mattbasta    schedule 04.08.2010


Ответы (4)


Лично мне переключатель кажется более читаемым. Вот причина:

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') {
}

or

case 'bar':
case 'baz':
case 'bat':
case 'buz':
    break;

С точки зрения производительности ... Что ж, не беспокойтесь о производительности. Если вы не выполняете несколько тысяч из них внутри жесткого цикла, вы даже не сможете заметить разницу (разница, скорее всего, будет в диапазоне микросекунд, если не ниже).

Выбирайте тот метод, который вы считаете наиболее читаемым. Это важная часть. Не пытайтесь микрооптимизировать. Помните, _5 _...

person ircmaxell    schedule 03.08.2010
comment
Будьте осторожны, этот переключатель даст вам ложные отрицательные и ложные срабатывания из-за неточного сравнения. Здесь switch - запах кода и угроза безопасности ipso facto. Вместо этого используйте ключи массива. - person Pacerier; 05.03.2015
comment
@Pacerier, почему коммутатор - это проклятие безопасности? - person ryabenko-pro; 21.03.2015
comment
@ ryabenko-pro, вольное сравнение даст вам тонкие ошибки: switch(0){case null: echo 'null'; break; default: echo 'not null';} - person Pacerier; 23.03.2015

Я знаю, что микрооптимизация - это плохо. Но как бы мне ни было любопытно, я провел небольшой тест, используя этот скрипт:

<?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");

Результирующие данные (для 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

Я запускал сценарий на своем старом и медленном компьютере с Windows с PHP 5.3.1 или 5.3.2, я не знаю, верно.

person NikiC    schedule 03.08.2010
comment
+1 за действия, направленные на попытку измерить разницу в производительности, чтобы дать верный ответ на вопрос. - person Kmeixner; 25.09.2014

Вам следует рассмотреть возможность использования полиморфизма в качестве альтернативы управляющим структурам, таким как if или switch. Это особенно удобно, если у вас очень много опций, так как это может значительно упростить логику управления.

Я писал о концепции здесь: http://codeutopia.net/blog/2009/02/02/avoiding-endless-switch-case-structures-with-classes/

person Jani Hartikainen    schedule 03.08.2010

Switch сообщает последующим читателям, что вы выполняете ветвление на основе значения одного значения, которое им пришлось бы подразумевать в противном случае, глядя на все условия. Поэтому я бы предпочел переключатель для ясности

person Nicolas78    schedule 03.08.2010