Имеет ли значение порядок обращений в операторах PHP switch?


В операторах PHP switch повышает ли производительность размещение более распространенных случаев вблизи вершины?

Например, предположим, что следующая функция вызывается 1000 раз:

<?php 
function foo_user ($op) {
    switch ($op) {
        case 'after_update':
        //Some Stuff
        case 'login':
        //Some other Stuff
    }
}

Если в 990 из 1000 случаев, когда функция вызывается аргументом $op является "login", улучшится ли производительность, если case: 'login' выше case 'after_update': в операторе switch? Например, будет ли код после case 'after_update': игнорироваться, если $op = login был передан?

Я провел несколько неофициальных тестов по этой идее, но разница была незначительной-возможно, потому, что код после case: 'login' и case 'after_update': тривиальны. Я бы предпочел избежать установки более обширного теста с нетривиальными операциями, если кто - то знает ответ прямо.

Это конкретно вопрос Drupal, но я думаю, что его может решить любой, кто знаком с оптимизацией PHP.

4 5

4 ответа:

Это, вероятно, будет называться микрооптимизацией. Я не думаю, что будет большая разница.

Однако порядок действительно много значит для логики случая переключения, если вы позволяете случаям проваливаться, Пример
switch ($var) {

    case 0:
    case 1:
       do_it();
       break;
    case 2:
       do_it_else();
       break;

}

Порядок важен, дело будет проваливаться и выполнять любой код, пока он не достигнет разрыва.

Я бы не беспокоился о скорости случая переключения, если бы у вас не было, скажем, 100 возможных случаев. Но если так, то, скорее всего, вы должны рефакторинг кода.

Вам понадобится намного больше, чем 1000 случаев, чтобы заметить разницу, Но да, есть разница. Я написал тест:

function test_switch($value) {

  $startTime = time() + microtime();

  for ($i = 0; $i < 10000000; $i++) {

    switch($value) {

    case "abcdefg":
      $j = $j + 1;
      break;
    case "hijklmno":
      $j = $j + 1;
      break;
    }
  }

  $endTime = time() + microtime();

  echo "Total time for argument $value: " . ($endTime - $startTime) . "<br>\n";
}

test_switch("abcdefg");
test_switch("hijklmno");

То есть 10 миллионов исполнений оператора switch. Вывод:

Total time for argument abcdefg: 3.99799704552
Total time for argument hijklmno: 5.38317489624

Так что разница есть, но она не будет заметна, пока вы не достигнете порядка 10 миллионов исполнений, в зависимости от вашего процессора, конечно.

Если вы не используете break; для закрытия каждого оператора, PHP будет продолжать оценивать случаи до конца блока switch, что может повлиять на производительность в достаточно большом блоке. Порядок тогда становится важным для получения поведения, которое вы ищете.

Из PHP.Net :

Оператор switch выполняет построчно (фактически, оператор за оператором). В самом начале код не выполняется. Только тогда, когда оператор case найден со значением, которое соответствует значение выражения switch не позволяет PHP начать выполнение инструкций. PHP продолжает выполнять операторы до тех пор, пока не завершится блок switch, или когда он впервые увидит оператор break. Если вы не напишете оператор break в конце списка операторов case, PHP продолжит выполнение операторов следующего case. Например:

<?php
    switch ($i) {
        case 0:
            echo "i equals 0";
        case 1:
            echo "i equals 1";
        case 2:
            echo "i equals 2";
    }
?>

Я бы предостерег от того, чтобы полагаться на это поведение, хотя и использовать break; для каждого case, поскольку это устранит некоторую двусмысленность, когда вы вернитесь к коду позже.

Обычно рекомендуется сначала написать наиболее вероятныйслучай , затем-второй...

Но, как писал Алекс,

Это, вероятно, будет называться a микро-оптимизация. Я не верю. это будет большая разница.