开发者

Nested ternary statements [duplicate]

开发者 https://www.devze.com 2023-04-10 10:21 出处:网络
This question already has answers here: Stacking Multiple Ternary Operators in PHP (11 answers) Closed 2 years ago.
This question already has answers here: Stacking Multiple Ternary Operators in PHP (11 answers) Closed 2 years ago.

I wonder why this works strange. I understand that the difference is grouping, but does it matter in comparison?

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

returns

last_row
none
开发者_开发知识库none
last_row

and

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

returns it correctly

first_row
none
none
last_row

Why is there a difference?


To use an explanation based on your code, a scaled down version would be:

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

In PHP, this is equivalent to writing:

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

On the first go, $i has the value of 0, so the first ternary returns 'first_row' and that string is used as the conditional for the second ternary -- which in boolean context evaluates to true -- hence 'last_row' is returned.

If you regroup it:

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

then the result of the first ternary will not interfere with the second ternary.


From the official PHP documentation:

"It is recommended that you avoid "stacking" ternary expressions. PHP's behaviour when using more than one ternary operator within a single statement is non-obvious"

Apparently, even though PHP's ternary operator (and much of its syntax otherwise) is based on C, for some reason PHP decided to make it left-associative, whereas in C and most other languages based on it, the ternary operator is right-associative:

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

So, yeah, I think we can safely conclude that PHP is just plain ass-backwards in (also) this respect.


See example 3 on 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.
?>

The important part being:

this is because ternary expressions are evaluated from left to right


Take a look at the answer provided by JRL. To be more clear about what is happening with your example you should understand that your expression is evaluated as such:

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

So when $i == 0 your statement essentially becomes this:

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

Since 'first_row' evaluates to true your 'last_row' is the result returned when $i == 0. When $i does not equal zero your statement essentially becomes this:

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

精彩评论

暂无评论...
验证码 换一张
取 消