2013-12-13 32 views
26

在PHP手册中,我找到“运算符”下的the following 'user contributed note'三元运算符左结合性

请注意,在PHP中,三元运算符?:具有左结合性,与C和C++不同,它具有右结合性。

你不能写这样的代码(如你在C/C++已经习惯了):

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

其实我尝试它,它真的打印four。但是我无法理解它背后的原因,仍然觉得它应该打印twoother

有人可以请解释这里发生了什么,以及为什么它打印'四'?

+3

添加关联隐含的括号,您将看到原因。 –

+3

问题的直观表示:http://i.imgur.com/1zgFd.jpg – Almo

回答

21

在任何理智的语言,三元运算符是右结合的,这样你会期待代码中这样解释:

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

然而,PHP三元运算符是古怪左联合,这样你的代码实际上等于这个:

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

如果它仍然不清楚,评估上是这样的:

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'; 
+2

我正确地阅读它,字符串被强制转换为布尔值吗? (如果是这样,哇。) – Wildcard

+0

@Wildcard否,这里的三元运算符被封装在'echo'中,它将打印到控制台。它会打印其中一个字符串,具体取决于$ a在方程中的评估方式。尽管我仍然没有得到“左”的联想性! –

+3

@DianaHolland,但*之前的部分*是一个字符串。 – Wildcard

19

因为整个表达式的计算结果就好像它是(......) ? 'four' : 'other'。由于第一个元素可能是truthy,它会给你'four'。在更加安全的语言中,?:具有正确的关联性,整个表达式的计算结果好像是$a == 1 ? 'one' : (......),如果$a不是1,则继续测试其他内容。

+1

当然,无论如何,你应该用圆括号表示复杂的表达式,所以在我看来,这一点是没有意义的。 –

+8

@NiettheDarkAbsol:在我看来,你应该为了可读性而加上括号。在我看来,OP中的代码是完全清晰的,以一种理智的(非PHP)语言表达,而且如果使用括号,它实际上变得更少。 – Amadan

+2

嵌套三元组太混乱,所以我从不使用它们,有或没有括号。但答案很好。 –

0

如果添加括号,问题就会解决。看下面的例子:
没有括号,当分数大于50时,分数总是D,但对于分数< = 49可以正常工作。
为了使程序正常工作,我添加了括号。如果输入这样的数字,知道输入多少个括号非常容易。

<?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")))) 
?> 
+4

除了需要添加圆括号,因为语言被破坏了,没有想到点... – Anthony

0

我无法从换我的头周围的例子:

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

所以我来到这里,我仍然不能换我的头周围,所以我有来贯穿它。

@amadan有最好的答案,imo。

这打印马,而不是火车。

// 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' ; 

如果我理解正确,你可以在步骤5中看到剩余的联想手段。

1

这就是我想出来帮助自己理解左vs.三元运算符的右结合。

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

这是作为反对:

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

如果你注意到,在PHP例子中,最里面的表现是在左边,而在第二个例子中,最里面的表达式在右边。每个步骤都会评估下一个最内层的表达式,直到出现单个结果。如果您要在PHP中嵌套三元运算,括号显然非常重要!