strange behaviour ternary operator

Coming from C# I must do a project in PHP.

I am using this code:

$transport = 'T';

$vehicle = (
 ( $transport == 'B' ) ? 'bus' :
 ( $transport == 'A' ) ? 'airplane' :
 ( $transport == 'T' ) ? 'train' :
 ( $transport == 'C' ) ? 'car' :
 ( $transport == 'H' ) ? 'horse' :
 'feet' );

echo $vehicle;

I would expect it to print train , but I get horse . Codepad example: http://codepad.org/rWllfrht

Who can explain this strange behaviour?


I won't advise you to use such code but for educational purposes it should be

$transport = 'T';
$vehicle = (
        ($transport == 'B') ? 'bus' : 
            (($transport == 'A') ? 'airplane' : 
                (($transport == 'T') ? 'train' : 
                        (($transport == 'C') ? 'car' : 
                                (($transport == 'H') ? 'horse' : 'feet'))))
        );

echo $vehicle;

A better code should be

$transport = 'T';
switch ($transport) {
    case 'A' :
        $vehicle = 'airplane';
        break;
    case 'B' :
        $vehicle = 'bus';
        break;
    case 'C' :
        $vehicle = 'car';
        break;
    case 'H' :
        $vehicle = 'horse';
        break;
    case 'T' :
        $vehicle = 'train';
        break;
    default :
        $vehicle = 'teleportation';
        break;
}

echo $vehicle;

Or better still:

$transport = 'T';
$array = array('A'=>'airplane','B'=>"bus","C"=>"car","H"=>"horse","T"=>"train");
echo isset($array[$transport]) ? $array[$transport] : null;

Or, use a database:

 SELECT name FROM transpotationTable WHERE someKey = '$transport' 

Not seeing any explanation about why your code is broken in the other answers, so here is a quick run-down.

The problem here is made more obvious is you add brackets to make the implicit order of evaluation more explicit.

Here's a trimmed down version of your code, which still produces the incorrect result of "horse":

 $t = 'T';

 ( $t == 'T' ) ? 'train' : 
 ( $t == 'C' ) ? 'car' : 
 ( $t == 'H' ) ? 'horse' : 'feet';

First, lets unroll it:

( $t == 'T' ) ? 'train' : ( $t == 'C' ) ? 'car' : ( $t == 'H' ) ? 'horse' : 'feet'; 

Next, I'll add explicit parenthesis where there are already implicit ones:

((($t == 'T') ? 'train' : ($t == 'C')) ? 'car' : ($t == 'H')) ? 'horse' : 'feet';

Next, we can resolve your comparisons:

((true ? 'train' : false) ? 'car' : false) ? 'horse' : 'feet';

You should start to see why this is broken. The first ternary evaluates true ? 'train' : 'false' true ? 'train' : 'false' to 'train' :

('train' ? 'car' : false) ? 'horse' : 'feet';

Because 'train' is true when cast to a boolean, the result is now 'car' :

'car' ? 'horse' : 'feet';

Again, because a non-empty string is "true", the result is now 'horse'. So, the first time a true comes up in your horrible nested case statement, the result will cascade through all remaining statements, throwing out the previous value for the "true" branch of the next operator.

The solution is to avoid this code. It is an attempt to be far, far too clever, and the result is a broken, unreadable mess. There is absolutely no reason to use it. Choose a switch statement, it's purpose built for exactly what you're trying to do.


This doesn't work as expected due to a bug in the PHP language grammar, as seen at: http://en.wikipedia.org/wiki/%3F:#PHP

Here's a simple version that DOES work:

$transport = 'T';

$vehicle = (
 ( $transport == 'B' ? 'bus' :
 ( $transport == 'A' ? 'airplane' :
 ( $transport == 'T'  ? 'train' :
 ( $transport == 'C'  ? 'car' :
 ( $transport == 'H'  ? 'horse' :
 'feet' ))))));

echo $vehicle;

But as everyone else said, I agree this isn't the best way to do this. You could use a switch case, if else if, or associative array and be a lot more readable.

链接地址: http://www.djcxy.com/p/9934.html

上一篇: 用于PHP的合并功能?

下一篇: 奇怪的行为三元运算符