web-dev-qa-db-fra.com

Meilleur moyen de faire un PHP passer avec plusieurs valeurs par cas?

Comment feriez-vous cette déclaration de commutateur PHP?

Notez également que ce sont des versions beaucoup plus petites, le 1 que je dois créer aura beaucoup plus de valeur ajoutée.

Version 1: 

switch ($p) { 
    case 'home': 
    case '': 
        $current_home = 'current';
    break; 

    case 'users.online': 
    case 'users.location': 
    case 'users.featured': 
    case 'users.new': 
    case 'users.browse': 
    case 'users.search': 
    case 'users.staff': 
        $current_users = 'current';
    break;

    case 'forum': 
        $current_forum = 'current';
    break; 
} 

Version 2: 

switch ($p) { 
    case 'home': 
        $current_home = 'current';
    break; 

    case 'users.online' || 'users.location' || 'users.featured' || 'users.browse' || 'users.search' || 'users.staff': 
        $current_users = 'current';
    break;

    case 'forum': 
        $current_forum = 'current';
    break; 
} 

UPDATE - Résultats des tests  

J'ai effectué des tests de vitesse sur 10 000 itérations, 

Time1: 0.0199389457703 // instructions If
Time2: 0.0389049446106 // instructions switch
Time3: 0.106977939606 // Tableaux 

63
JasonDavis

Pour toute situation où vous avez une chaîne inconnue et que vous devez déterminer laquelle des chaînes autres auxquelles elle correspond, la seule solution qui ne soit pas ralentie à mesure que vous ajoutez d'autres éléments consiste à utiliser un tableau. , mais ont toutes les chaînes possibles comme clés. Ainsi, votre commutateur peut être remplacé par ce qui suit:

// used for $current_home = 'current';
$group1 = array(
        'home'  => True,
        );

// used for $current_users = 'current';
$group2 = array(
        'users.online'      => True,
        'users.location'    => True,
        'users.featured'    => True,
        'users.new'         => True,
        'users.browse'      => True,
        'users.search'      => True,
        'users.staff'       => True,
        );

// used for $current_forum = 'current';
$group3 = array(
        'forum'     => True,
        );

if(isset($group1[$p]))
    $current_home = 'current';
else if(isset($group2[$p]))
    $current_users = 'current';
else if(isset($group3[$p]))
    $current_forum = 'current';
else
    user_error("\$p is invalid", E_USER_ERROR);

Cela n'a pas l'air aussi propre qu'une switch(), mais c'est la seule solution fast qui n'inclut pas l'écriture d'une petite bibliothèque de fonctions et de classes pour la garder ordonnée. Il est toujours très facile d’ajouter des éléments aux tableaux.

49
too much php

La version 2 ne fonctionne pas !!

case 'users.online' || 'users.location' || ...

est exactement le même que:

case True:

et que case sera choisi pour toute valeur de $p, à moins que $p ne soit la chaîne vide.

|| N'a aucune signification particulière dans une instruction case, vous ne comparez pas $p à chacune de ces chaînes, vous vérifiez simplement si ce n'est pas False.

25
too much php

Placez ces nombreuses valeurs dans un tableau et interrogez-le, car le casse semble masquer la sémantique sous-jacente de ce que vous essayez d'obtenir lorsqu'une variable chaîne est utilisée comme condition, ce qui rend plus difficile la lecture et la compréhension, par exemple :

$current_home = null;
$current_users = null;
$current_forum = null;

$lotsOfStrings = array('users.online', 'users.location', 'users.featured', 'users.new');

if(empty($p)) {
    $current_home = 'current';
}

if(in_array($p,$lotsOfStrings)) {
    $current_users = 'current';
}

if(0 === strcmp('forum',$p)) {
    $current_forum = 'current';
}
8
karim79

Si quelqu'un d'autre devait maintenir votre code, il ferait certainement une double-prise sur la version 2 - c'est extrêmement non standard.

Je resterais avec la version 1. Je suis de l’école de bien que les déclarations de cas sans bloc de déclaration devrait avoir un commentaire explicite // fall through à côté d’eux pour indiquer qu’il est effectivement votre intention de passer à travers, éliminant ainsi toute ambiguïté de si vous alliez gérer les cas différemment et oublié ou quelque chose.

4
Mark Rushakoff

Par souci d’exhaustivité, je ferai remarquer que la logique brisée de la "Version 2" peut être remplacée par une instruction switch qui fonctionne et également utiliser des tableaux à la fois pour la vitesse et la clarté, comme suit:

 // utilisé pour $ current_home = 'current'; 
 $ home_group = array (
 'home' => True, 
); 

 // utilisé pour $ current_users = 'current'; 
 $ user_group = array (
 'users.online' => True, 
 'users.location' => True, 
 'users.featured' => True, 
 'users.new' => True, 
 'users.browse' => True, 
 'users.search' => True, 
 'users.staff' => True, 
) ; 

 // utilisé pour $ current_forum = 'current'; 
 $ forum_group = array (
 'forum' => True, 
); 

 switch (true ) {
 case isset ($ home_group [$ p]): 
 $ current_home = 'current'; 
 Pause;
 case isset ($ user_group [$ p]): 
 $ current_users = 'current'; 
 Pause;
 case isset ($ forum_group [$ p]): 
 $ current_forum = 'current'; 
 Pause;
 défaut:
 erreur_utilisateur ("\ $ p n'est pas valide", E_USER_ERROR); 
} 
4
Peter

La version 1 est certainement plus facile pour les yeux, plus claire quant à vos intentions, et plus facile à ajouter aux conditions de cas.

Je n'ai jamais essayé la deuxième version. Dans de nombreuses langues, cela ne serait même pas compilé car chaque étiquette de cas doit être évaluée à une expression constante.

3
Robert Cartaino

Quelques autres idées non encore mentionnées:

switch(true){ 
  case in_array($p, array('home', '')): 
    $current_home = 'current'; break;

  case preg_match('/^users\.(online|location|featured|new|browse|search|staff)$/', $p):
    $current_users = 'current'; break;

  case 'forum' == $p:
    $current_forum = 'current'; break; 
}

Quelqu'un se plaindra probablement de problèmes de lisibilité avec # 2, mais je n'aurais aucun problème à hériter d'un tel code.

3
pguardiario

Aucune version 2 ne fonctionne réellement, mais si vous voulez ce type d’approche, vous pouvez procéder comme suit (probablement pas le plus rapide, mais sans doute plus intuitif):

switch (true) {
case ($var === 'something' || $var === 'something else'):
// do some stuff
break;
}

1
tomfumb

Je préfère définitivement la version 1. La version 2 peut nécessiter moins de lignes de code, mais il sera extrêmement difficile à lire une fois que vous aurez beaucoup de valeurs, comme vous le prédisez.

(Honnêtement, je ne savais même pas que la version 2 était légale jusqu'à présent. Je ne l'avais jamais vue ainsi.)

1
Josh Leitzel

En combinaison avec variables variables, vous aurez plus de flexibilité:

<?php
$p = 'home'; //For testing

$p = ( strpos($p, 'users') !== false? 'users': $p);
switch ($p) { 
    default:
        $varContainer = 'current_' . $p; //Stores the variable [$current_"xyORz"] into $varContainer
        ${$varContainer} = 'current'; //Sets the VALUE of [$current_"xyORz"] to 'current'
    break;

}
//For testing
echo $current_home;
?>

Pour en savoir plus, consultez variables variables et les exemples que j'ai soumis au manuel php:
Exemple 1: http://www.php.net/manual/fr/language.variables.variable.php#105293
Exemple 2: http://www.php.net/manual/fr/language.variables.variable.php#105282

PS: Cet exemple de code est SMALL AND SIMPLE, exactement comme je l’aime. C'est testé et fonctionne aussi

0
Omar

Je pense que la version 1 est la voie à suivre. C'est beaucoup plus facile à lire et à comprendre. 

0
Josh Curren

peut être

        switch ($variable) {
        case 0:
            exit;
            break;
        case (1 || 3 || 4 || 5 || 6):
            die(var_dump('expression'));
        default:
            die(var_dump('default'));
            # code...
            break;
    }
0
Timenty Ogurtsov
if( in_array( $test, $array1 ) )
{
    // do this
}
else if( stristr( $test, 'commonpart' ) )
{
    // do this
}
else
{
    switch( $test )
    {
        case 1:
            // do this
            break;
        case 2:
            // do this
            break;
        default:
            // do this
            break;
    }
}
0
AnOldMan

De nos jours tu peux faire ...

switch ([$group1, $group2]){
    case ["users", "location"]:
    case ["users", "online"]:
        Ju_le_do_the_thing();
        break;
    case ["forum", $group2]:
        Foo_the_bar();
        break;
}
0
liljoshu