web-dev-qa-db-fra.com

Associativité gauche de l'opérateur ternaire

Dans le manuel PHP, je trouve la "note contributive de l'utilisateur" suivante sous "Opérateurs".

Notez que dans php, l'opérateur ternaire?: A une associativité à gauche contrairement à C et C++ où il a une associativité à droite.

Vous ne pouvez pas écrire du code comme celui-ci (comme vous l’avez peut-être habitué en C/C++):

<?php 
$a = 2; 
echo ( 
    $a == 1 ? 'one' : 
    $a == 2 ? 'two' : 
    $a == 3 ? 'three' : 
    $a == 4 ? 'four' : 'other'); 
echo "\n"; 
// prints 'four' 

En fait, je l’essaye et il affiche vraiment four. Cependant, je ne comprenais pas la raison derrière cela et pensais toujours que cela devrait imprimer two ou other.

Quelqu'un peut-il s'il vous plaît expliquer ce qui se passe ici et pourquoi il affiche "quatre"?

34
Kapil Sharma

Dans n'importe quel langage rationnel, l'opérateur ternaire est à droite associative, de sorte que vous auriez attendu votre code à interpréter comme ceci:

$a = 2;
echo ($a == 1 ? 'one' :
     ($a == 2 ? 'two' :
     ($a == 3 ? 'three' :
     ($a == 4 ? 'four' : 'other'))));    # prints 'two'

Cependant, l'opérateur ternaire PHP est étrangement associé à gauche, de sorte que votre code est en réalité équivalent à ceci:

<?php
$a = 2;
echo (((($a == 1  ? 'one' :
         $a == 2) ? 'two' :
         $a == 3) ? 'three' :
         $a == 4) ? 'four' : 'other');   # prints 'four'

Au cas où ce n’est pas encore clair, l’évaluation se déroule comme suit:

echo ((((FALSE    ? 'one' :
         TRUE)    ? 'two' :
         $a == 3) ? 'three' :
         $a == 4) ? 'four' : 'other');

echo ((( TRUE     ? 'two' :
         $a == 3) ? 'three' :
         $a == 4) ? 'four' : 'other');

echo ((  'two'    ? 'three' :
         $a == 4) ? 'four' : 'other');

echo (    'three' ? 'four' : 'other');

echo 'four';
37
200_success

Parce que votre expression entière est évaluée comme si c'était (......) ? 'four' : 'other'. Puisque le premier élément est probablement quelque chose de vrai, il vous donne 'four'. Dans les langages plus propres, où ?: a une associativité de droite, l'expression entière est évaluée comme si elle était $a == 1 ? 'one' : (......), où si $a n'est pas 1, vous testez d'autres éléments.

20
Amadan

C'est ce que j'ai proposé pour m'aider à comprendre l'associativité gauche/droite de l'opérateur ternaire.

// PHP

$a = "T";
$vehicle =  $a == "B" ? "bus" :
            $a == "A" ? "airplane" :
            $a == "T" ? "train" :
            $a == "C" ? "car" :
            $a == "H" ? "horse" : "feet";

            // (as seen by the PHP interpreter)
            // INITIAL EXPRESSION: ((((($a == "B" ? "bus" : $a == "A") ? "airplane" : $a == "T") ? "train" : $a == "C") ? "car" : $a == "H") ? "horse" : "feet");
            // STEP 1:             (((((FALSE ? "bus" : FALSE) ? "airplane" : TRUE) ? "train" : FALSE) ? "car" : FALSE) ? "horse" : "feet")
            // STEP 2:             ((((FALSE ? "airplane" : TRUE) ? "train" : FALSE) ? "car" : FALSE) ? "horse" : "feet")
            // STEP 3:             (((TRUE ? "train" : FALSE) ? "car" : FALSE) ? "horse" : "feet")
            // STEP 4:             (("train" ? "car" : FALSE) ? "horse" : "feet")
            // STEP 5:             ("car" ? "horse" : "feet")
            // FINAL EVALUATION:   ("horse")

            // If you used the initial expression here (with the parenthesis) in a different language, it would also evaluate to "horse."

echo $vehicle; // gives us "horse"

Ceci est opposé à:

// EVERY OTHER LANGUAGE

var a = "T";
var vehicle =   a == "B" ? "bus" :
                a == "A" ? "airplane" :
                a == "T" ? "train" :
                a == "C" ? "car" :
                a == "H" ? "horse" : "feet";

                // (as seen by the other language's interpreter)
                // INITIAL EXPRESSION: (a == "B" ? "bus" : (a == "A" ? "airplane" : (a == "T" ? "train" : (a == "C" ? "car" : (a == "H" ? "horse" : "feet")))));
                // STEP 1:             (FALSE ? "bus" : (FALSE ? "airplane" : (TRUE ? "train" : (FALSE ? "car" : (FALSE ? "horse" : "feet")))))
                // STEP 2:             (FALSE ? "bus" : (FALSE ? "airplane" : (TRUE ? "train" : (FALSE ? "car" : "feet"))))
                // STEP 3:             (FALSE ? "bus" : (FALSE ? "airplane" : (TRUE ? "train" : "feet")))
                // STEP 4:             (FALSE ? "bus" : (FALSE ? "airplane" : "train"))
                // STEP 5:             (FALSE ? "bus" : "train")
                // FINAL EVALUATION:   ("train")

                // If you used the initial expression here (with the parenthesis) in PHP, it would also evaluate to "train."

console.log(vehicle); // gives us "train"

Si vous remarquez que, dans l'exemple PHP, l'expression la plus interne est à gauche, et dans le second exemple, l'expression la plus interne est à droite. Chaque étape évalue la prochaine expression la plus profonde jusqu'à obtenir un résultat unique. Les parenthèses sont clairement très importantes si vous allez imbriquer des opérations ternaires en PHP!

2
Jonathon

Si vous ajoutez des parenthèses, le problème sera résolu. Regardez l'exemple suivant:
Sans les parenthèses, la note est toujours D lorsque les notes sont supérieures à 50, mais cela fonctionne très bien pour les notes <= 49.
Pour que le programme fonctionne comme il se doit, j’ai ajouté des parenthèses. Il est très facile de savoir combien de parenthèses il faut entrer s’il est tapé ainsi.

<?php
 $marks_obtained = 65;
 $grade = null;
 //Use parentheses () otherwise the final grade shown will be wrong.
//Excluding the first line, for each additional line, 
//we add a parenthesis at the beginning of each line and a parenthesis at the end of the statement.
echo $grade = $marks_obtained >= 90 && $marks_obtained <= 100 ?  "A+"
              : ($marks_obtained <= 89 && $marks_obtained >= 80 ? "A"
              : ($marks_obtained <= 79 && $marks_obtained >= 70 ? "B"
              : ($marks_obtained <= 69 && $marks_obtained >= 60 ? "C"
              : ($marks_obtained <= 59 && $marks_obtained >= 50 ? "D"
              :                                                     "F"))))
?>
0
Dillshad Rana

Je ne pouvais pas envelopper l’exemple de:

https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/

Alors je suis venu ici et je ne pouvais toujours pas comprendre ce que je pensais, alors j'ai dû le traverser.

@amadan a la meilleure réponse, imo.

Ceci imprime cheval, pas train.

// 0
$arg = 'T';
$vehicle = 
    $arg == 'B' ? 'bus' :
    $arg == 'A' ? 'airplane' :
    $arg == 'T' ? 'train' :
    $arg == 'C' ? 'car' :
    $arg == 'H' ? 'horse' :
    'feet' ;
// 1
$vehicle = 
>   FALSE       ? 'bus' :
    $arg == 'A' ? 'airplane' :
    $arg == 'T' ? 'train' :
    $arg == 'C' ? 'car' :
    $arg == 'H' ? 'horse' :
    'feet' ;

// 2
$vehicle = 
    FALSE       ? 'bus' :
>   FALSE       ? 'airplane' :
    $arg == 'T' ? 'train' :
    $arg == 'C' ? 'car' :
    $arg == 'H' ? 'horse' :
    'feet' ;

// 3
$vehicle = 
>   (FALSE? 'bus' : FALSE? 'airplane' : TRUE)? 'train' :
    $arg == 'C' ? 'car' :
    $arg == 'H' ? 'horse' :
    'feet' ;

// 4
$vehicle = 
>   true ? 'train' :
    $arg == 'C' ? 'car' :
    $arg == 'H' ? 'horse' :
    'feet' ;

// 5 
$vehicle = 
>   ('train' : $arg == 'C') ? 'car' :
    $arg == 'H' ? 'horse' :
    'feet' ;

// 6 
$vehicle = 
>   (true ? 'car' : $arg == 'H') ? 'horse' :
    'feet' ;

// 7 
$vehicle = 
>   (true) ? 'horse' : 'feet' ;

Vous pouvez voir ce que signifie associatif gauche à l'étape 5, si je comprends bien.