Understanding nested PHP ternary operator

孤街浪徒 提交于 2019-11-26 20:43:52

You need to bracket the ternary conditionals:

<?php

for ($a=0; $a < 7; $a++) {
  echo (
    $a == 1 ? 'one' :
    ($a == 2 ? 'two' :
    ($a == 3 ? 'three' :
    ($a == 5 ? 'four' : 'other'))));
    echo "\n";
    // prints 'four'
}
exit;
?>

returns:

other
one
two
three
other
four
other

as you'd expect.

See the note at the bottom of "Ternary operators" at PHP Ternary operator help.

The expressions are being evaluated left to right. So you are actually getting:

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

So for $a=2, you get:

  echo (
    ((($a==2) ? 'two' : $a == 3) ? 'three' :
    $a == 5) ? 'four' : 'other');

and then

  echo (
    ((true ? 'two' : $a == 3) ? 'three' :
    $a == 5) ? 'four' : 'other');

and then

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

and then

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

and so echo 'four'.

Remember that PHP is dynamically typed and treats any non-zero non-null values as TRUE.

Samuel

On the Comparison Operators page in the PHP Manual they explain that PHP's behavior is "non-obvious" when nesting (stacking) ternary operators.

The code you've written is like this:

$a = 2;

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

// prints 'four'

As $a is 2 and both 'two' and 'three' are TRUE as well, you get "four" as the result, as you don't compare any longer if 'four' is TRUE or not.

If you want to change that, you have to put the brackets at different places [also noted by: BeingSimpler and MGwynne]:

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

// prints 'two'

Problem with grouping conditions, just need to add brackets to separate them.

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

Solved.

This is what I came up with to help myself understand left vs. right associativity for the ternary operator.

// 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"

This is as opposed to:

// 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"

If you notice, in the PHP example, the innermost expression is on the left, and on the second example, the innermost expression is on the right. Each step evaluates the next innermost expression until there is a single result. Parenthesis are clearly very important if you're going to nest ternary operations in PHP!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!