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';
精彩评论