Оптимизация оператора switch в PHP 7.2

В статье Что нового в PHP 7.2 мы рассмотрели основные изменения новой версии php, релиз которой ожидается в конце ноября. Сегодня мы рассмотрим небольшую, но полезную оптимизацию оператора switch, добавленную в php 7.2. Эта статья является вольным переводом статьи PHP 7.2’s «switch» optimisations от Дерика Ретанса, автора Xdebug и других полезных инструментов для php.

Как было до PHP 7.2

До версии 7.2, php выполнял выражения case по порядку. Рассмотрим следующий простой пример:

$cc = "no";
switch ( $cc )
{
    case 'de': echo "DEUTSCH"; break;
    case 'en': echo "English"; break;
    case 'nl': echo "Nederlands"; break;
    case 'no': echo "Norsk"; break;
    default:
        echo "unknown"; break;
}

Для интерпретатора php выполнение этого кода аналогично следующему:

$cc = "no";
if ($cc == 'de') {
    echo "DEUTSCH";
} elseif ($cc == 'en') {
    echo "English";
} elseif ($cc == 'nl') {
    echo "Nederlands";
} elseif ($cc == 'no') {
    echo "Norsk";
} else {
    echo "unknown"; break;
}

Да, php сравнивает переменную $cc с каждым значением case по очереди. Это означает, что если наиболее часто используемое значение case находится в конце списка, то код тратит процессорное время в пустую.

Оптимизация оператора switch в PHP 7.2

В php 7.2 добавилась оптимизация, преобразующая такую последовательность if-ов в таблицу переходов. Стоит заметить, что это работает, если все значения case являются только строками, или только числами. Если в условиях case есть значения разных типов, то оператор switch будет работать так же, как и в предыдущих версиях php.

Так как php не поддерживает оператор goto, рассмотрим как это работает с помощью следующего псевдокода:

$cc = "no";
$_table = [ "de" => 1, "en" => 2, "nl" => 3, "no" => 4 ];
if (gettype($cc) == 'string') {
    if (array_key_exists($cc, $_table)) {
        goto "jmp_{$_table[$cc]}";
    } else {
        goto jmp_default;
    }
} else {
    /* do original if/else if/else sequence */
}
jmp_1: echo "DEUTSCH"; goto end;
jmp_2: echo "English"; goto end;
jmp_3: echo "Nederlands"; goto end;
jmp_4: echo "Norsk"; goto end;
jmp_default: echo "unknown";
end;

В этом примере видно, что если значение $cc является строкой, то будет использована таблица переходов $_table для немедленного перехода к выполнению кода, соответствующего нужно условию case. Если $cc — не строка, будут выполнены обычные сравнения if/else.

Заключение

Данная оптимизация является очень полезным обновлением, особенно если в коде используются длинные списки switch/case.

Протестировать новую версию php можно с помощью официального docker-контейнера PHP.

Оптимизация оператора switch в PHP 7.2: 2 комментария

    1. Даже в ООП должно быть место, где выбирается конкретная реализация. И тут без условных операторов не обойтись.

Добавить комментарий