Le temps passe et les choses évoluent. PHP est en version 7.2 et la version 7.3 arrive à grands pas (sans parler de PHP8)...
Je vous invite grandement à suivre l'actualité et les conférences de l'AFUP, mais ça vous le savez.
Pour les personnes que j'ai formées, vous connaissez mon obsession pour les performances. Jusqu'à cette rentrée 2018, la condition if...elseif...else
était plus rapide en PHP que switch. Et bien sachez qu'à partir de PHP 7.2 les choses changent et switch
est plus rapide pour faire des comparaisons simples a === b, c...
La différence n'était évidemment pas flagrante dans l'utilisation courante mais elle était bien là.
À partir de PHP 7.2, les switch font donc leur grand retour ! De nombreuses optimisations ont été apportées à opcache mais certaines ont été directement implémentées dans PHP lui-même comme celle-ci.
Avant PHP 7.2, PHP considérait chaque déclaration case dans l'ordre. Imaginons que nous avons le code suivant (code banal) :
$cc = 'no';
switch ( $cc ) {
case 'fr':
echo 'French';
break;
case 'en':
echo 'English';
break;
case 'nl':
echo 'Nederlands';
break;
case 'no':
echo 'Norsk';
break;
default:
echo 'unknown';
break;
}
L'interpréteur de PHP aborde l'exécution de cette structure switch
comme si elle était écrite comme cela :
$cc = 'no';
if ($cc == 'fr') {
echo 'French';
} elseif ($cc == 'en') {
echo 'English';
} elseif ($cc == 'nl') {
echo 'Nederlands';
} elseif ($cc == 'no') {
echo 'Norsk';
} else {
echo 'unknown';
}
Eh oui ! Il comparait la variable $cc
pour chaque déclaration case
une par une. Cela signifie que si votre cas le plus fréquent se trouve tout en bas de la liste, vous perdez du temps CPU inutilement.
PHP 7.2 apporte une optimisation qui convertit cette séquence de déclarations if
en une jump table
si tous les case
sont soit des entiers soit des chaînes de caractères. Si on regarde le pseudo-code, on obtient quelque chose comme cela :
$cc = 'no';
$_table = ['fr' => 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 {
/* fait la séquence if/else if/else originale */
}
jmp_1:
echo 'French';
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:
Cet exemple nous montre que tant que $cc
est une chaîne de caractères, il va utiliser la jump table $_table
pour sauter (avec goto
) immédiatement au code représentant la déclaration case
. Si $cc
n'est pas une chaîne de caractères, il fera alors la dance if/elseif/else
habituelle. Et dans ce cas-là, il arrivera peut-être jusqu'à votre cas le plus fréquent mis dans le default.
Voilà donc une grande optimisation !
0