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',
    };
}

Vous aimeriez progresser en PHP ? Mais vous ne savez pas comment vous y prendre ?

S'entraîner pour progresser en PHP

Mon programme "S'entraîner pour progresser en PHP" est disponible. Il vous permettra de recevoir chaque semaine un kata de code directement dans votre boîte mail, ainsi que des aides à la réalisation, des vidéos explicatives et des défis supplémentaires.

Reçois dès maintenant un kata gratuit en cliquant sur le bouton ci-dessous.