Вложенные троичные выражения - PullRequest
9 голосов
/ 05 октября 2011

Интересно, почему это работает странно.Я понимаю, что разница заключается в группировке, но имеет ли это значение для сравнения?

$i = 0;
foreach ($items as $item) {
   echo ($i == 0) ? 'first_row' : ($i == sizeof($feedbacks)-2) ? 'last_row' : 'none';
   $i++;
}

возвращает

last_row
none
none
last_row

и

$i = 0;
foreach ($items as $item) {
   echo ($i == 0) ? 'first_row' : (($i == sizeof($feedbacks)-2) ? 'last_row' : 'none');
   $i++;
}

возвращает ее правильно

first_row
none
none
last_row

Почему есть разница?

Ответы [ 4 ]

14 голосов
/ 05 октября 2011

Чтобы использовать объяснение, основанное на вашем коде, уменьшенная версия будет:

for ($i=0; $i<5; $i++) {
   echo $i == 0 ? 'first_row' : $i == 4 ? 'last_row' : 'none';
}

В PHP это эквивалентно написанию:

for ($i=0; $i<5; $i++) {
   echo ($i == 0 ? 'first_row' : $i == 4) ? 'last_row' : 'none';
}

На первом шаге $i имеет значение 0, поэтому первый троичный символ возвращает 'first_row', и эта строка используется в качестве условного для второго троичного символа - который в логическом контексте оценивается как true - следовательно 'last_row' возвращается.

Если вы перегруппируете это:

for ($i=0; $i<5; $i++) {
   echo $i == 0 ? 'first_row' : ($i == 4 ? 'last_row' : 'none');
}

тогда результат первого троичного не будет мешать второму троичному.

4 голосов
/ 05 октября 2011

Из официальной документации PHP :

"Рекомендуется избегать" укладки "тернарных выражений. Поведение PHP при использовании более одного троичного оператора в одном выражениинеочевидно "

По-видимому, хотя троичный оператор PHP (и большая часть его синтаксиса в противном случае) основан на C, по какой-то причине PHP решил сделать его левоассоциативным , тогда как в C и большинстве других языков на его основе троичный оператор является ассоциативно-правым :

C:

$ cat /tmp/foo.c
#include <stdio.h>
void main (void) { printf("%s\n", ( 1 ? "foo" : 0 ? "bar" : "baz" ) ); }

$ gcc -o /tmp/foo /tmp/foo.c; /tmp/foo
foo

Perl:

$ perl -e 'print ( 1 ? "foo" : 0 ? "bar" : "baz" ) . "\n";'
foo

Java:

$ cat /tmp/foo.java
public class foo { public static void main(String[] args) {
    System.out.println( ( true ? "foo" : false ? "bar" : "baz" ) );
} }

$ javac -d /tmp /tmp/foo.java; java -cp /tmp foo
foo

JavaScript:

$ cat /tmp/foo.js
print( 1 ? "foo" : 0 ? "bar" : "baz" );

$ rhino -f /tmp/foo.js
foo

PHP:

$ php -r 'echo ( 1 ? "foo" : 0 ? "bar" : "baz" ) . "\n";'
bar

Так что, да, я думаю, мы можем с уверенностью сделать вывод, что PHP является просто задом наперед (и) в этом отношении.

3 голосов
/ 05 октября 2011

См. пример 3 на php.net :

<?php
// on first glance, the following appears to output 'true'
echo (true?'true':false?'t':'f');

// however, the actual output of the above is 't'
// this is because ternary expressions are evaluated from left to right

// the following is a more obvious version of the same code as above
echo ((true ? 'true' : false) ? 't' : 'f');

// here, you can see that the first expression is evaluated to 'true', which
// in turn evaluates to (bool)true, thus returning the true branch of the
// second ternary expression.
?>

Важная часть:

это потому, что троичные выражения вычисляются слева направо

0 голосов
/ 05 октября 2011

Взгляните на ответ, предоставленный JRL. Чтобы быть более ясным в отношении того, что происходит с вашим примером, вы должны понимать, что ваше выражение оценивается так:

echo (($i == 0) ? 'first_row' : ($i == sizeof($feedbacks)-2)) ? 'last_row' : 'none';

Итак, когда $i == 0 ваше утверждение по сути становится таким:

echo 'first_row' ? 'last_row' : 'none';

Поскольку 'first_row' оценивается как true, ваш 'last_row' является результатом, возвращаемым при $i == 0. Когда $i не равен нулю, ваше утверждение по сути становится следующим:

echo ($i == sizeof($feedbacks)-2) ? 'last_row' : 'none';
...