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

Tu aimerais progresser en PHP ? Mais tu ne sais pas comment t'y prendre ?

S'entraîner pour progresser en PHP

Mon programme "S'entraîner pour progresser en PHP" va bientôt ouvrir ses portes. Il te permettra de recevoir chaque semaine un kata de code directement dans ta boîte mail, ainsi que des aides à la réalisation, des vidéos explicatives, voire des live coding et de la review.

Si tu es intéressé(e), clique sur le bouton ci-dessous pour avoir plus d'informations et t'inscrire afin d'être prévenu(e) de l'ouverture de ce programme.