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" a ouvert 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 nous rejoindre !