2013-12-13 2 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. Однако я не мог понять причину этого и все еще чувствую, что он должен печатать two или other.

Может кто-нибудь объяснить, что здесь происходит и почему он печатает «четыре»?

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

в случае, если это все еще не ясно, что evaluati на выглядит следующим образом:

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 no, тернарный оператор здесь завернут в 'echo', который будет печатать на консоли. он будет печатать одну из строк, в зависимости от того, как '$ a' оценивается в уравнениях. Я все еще не получаю «левую» ассоциативность! –

+3

@DianaHolland, но часть * before * '?' Является строкой. – Wildcard

19

Потому что все ваше выражение оценивается так, как если бы оно было (......) ? 'four' : 'other'. Поскольку первый элемент, вероятно, является чем-то правдоподобным, он дает вам 'four'. В более известных языках, где ?: имеет правую ассоциативность, все выражение оценивается так, как если бы оно было $a == 1 ? 'one' : (......), где, если $a не 1, вы продолжаете проверять другие вещи.

+1

Конечно, в любом случае вы должны заключить в круглые скобки свои сложные выражения, поэтому, на мой взгляд, точка спорная. –

+8

@NiettheDarkAbsol: На мой взгляд, вы должны быть в скобках для удобства чтения. Код в OP совершенно разборчив, на мой взгляд, на нормальном (не PHP) языке, и на самом деле это становится меньше, если вы используете круглые скобки. – Amadan

+2

Вложенные тройники слишком запутанны, поэтому я никогда не пользуюсь ими, с круглыми скобками или без них. Но ответ велик. –

0

Если вы добавите круглые скобки, проблема будет решена. Посмотрите на следующий пример:
Без круглых скобок класс всегда D, если метки больше 50, но отлично подходит для меток < = 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

Это то, что я придумал, чтобы помочь себе понять левые против.правая ассоциативность для тернарного оператора.

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

Смежные вопросы