Attention au switch

Sauriez-vous trouver la différence de résultat entre ces deux codes ?

function getStatusByCode($code)
{	
    $status = '';
    
    switch ($code) {
        case 0:
            $status = 'OK';
            break;
            
        case 1: 
            $status = 'ALERTE';
            break;
            
        default:
            $status = 'INDETERMINE';
            break;
    }    
    
    return $status;
}

var_dump(getStatusByCode(null));
function getStatusByCode($code)
{	
    $status = '';
    
    if ($code === 0) {
        $status = 'OK';
    } elseif ($code === 1) {
        $status = 'ALERTE';
    } else {
        $status = 'INDETERMINE';
    }
    
    return $status;
}

var_dump(getStatusByCode(null));

Alors avez-vous trouvé ?

  • Dans le premier cas avec le switch, la méthode retourne OK.
  • Dans le deuxième cas, la méthode retourne INDETERMINE.

Mais pourquoi cette différence ?

Le premier code avec le switch est issu d'une base de code legacy : pas de type hinting sur les arguments, pas de retour de la fonction. Et ce code était la cause d'un petit bug, car switch utilise la comparaison large : utilisation de == au lieu de === pour comparer les valeurs.

Et donc en PHP avec la comparaison large, null équivaut à 0.

Donc faite attention quand vous avez une suite de if / elseif / else, le passage en switch peut avoir un impact sur le comportement attendu.

Alors que faire ?

Si vous avez l'habitude de me suivre un peu, je vous recommande d'utiliser le plus souvent (pour ne pas dire tout le temps), la comparaison stricte avec ===.

Donc si vous voulez garder ce comportement, quelques pistes :

  • Vous laissez votre suite de if / elseif / else
  • Vous renforcez les paramètres de votre fonction avec des types afin de vous assurer de n'avoir jamais de valeur non voulue (si c'est bien le cas)
function getStatusByCode(int $code)
{	
    $status = '';
    
    switch ($code) {
        case 0:
            $status = 'OK';
            break;
            
        case 1: 
            $status = 'ALERTE';
            break;
            
        default:
            $status = 'INDETERMINE';
            break;
    }    
    
    return $status;
}

var_dump(getStatusByCode(null));

/* Résultat : Fatal error: Uncaught TypeError: 
 * Argument 1 passed to getStatusByCode() must be of the type int, null given
 */
  • Vous utilisez match disponible depuis PHP 8 qui utilise la comparaison stricte 👍
function getStatusByCode($code)
{
    return match($code) {
        0 => 'OK',
        1 => 'ALERTE',
        default => 'INDETERMINE',
    };
}

Cet article t'a plu ? Si oui, je te propose de t'inscrire à ma dev letter pour recevoir régulièrement dans ta boîte mail mes conseils, mes nouveaux articles, des vidéos à voir, des outils à découvrir et encore bien d’autres choses.

Je m'inscris