• 3
name

A PHP Error was encountered

Severity: Notice

Message: Undefined index: userid

Filename: views/question.php

Line Number: 191

Backtrace:

File: /home/prodcxja/public_html/questions/application/views/question.php
Line: 191
Function: _error_handler

File: /home/prodcxja/public_html/questions/application/controllers/Questions.php
Line: 433
Function: view

File: /home/prodcxja/public_html/questions/index.php
Line: 315
Function: require_once

name Punditsdkoslkdosdkoskdo

Stacking Multiple Ternary Operators in PHP

This is what I wrote :

 $Myprovince = (
($province == 6) ? "city-1" :
($province == 7) ? "city-2" :
($province == 8) ? "city-3" :
($province == 30) ? "city-4" : "out of borders"
);

But for every field I got the value city-4. I want to use ternary operators instead of switch/if because I want to experiment and see how it would be done.

What's the problem with this code?

      • 2
    • Using ternary operators with complex nested conditions is not recommended for very good reasons... because they're fraught with problems, and it's extremely difficult to identify bugs. You've just discovered this! If you really knew how to use them, you wouldn't be asking for help! So why do you still want to use ternary operators in this case?
    • god , please , I WOULD NOT USE THIS Method in a live script , never ever , are you better now ? just curious how to use it :D

Others have already suggested the right way of doing it but if you really want to use ternary operator you need to use parenthesis as:

$province = 7;
 $Myprovince = (
 ($province == 6) ? "city-1" :
  (($province == 7) ? "city-2" :
   (($province == 8) ? "city-3" :
    (($province == 30) ? "city-4" : "out of borders")))
 );

Updated Link

  • 91
Reply Report
      • 2
    • shudder I'd +1 your bravery for typing that out, but can't bring myself to "endorse" such a hideous thing...
    • @Mac Taylor: You are using the wrong tool for the job. There is nothing more to say about it. You could also create the string 'abc' with string concatenation 'a'.'b'.'c', but why doing so? Have fun adding a new city to your ternary beast and don't forget to count to match the parenthesis!
      • 2
    • I think it is not a good response to reject the use of chained ternary as a programming pattern. It makes for concise clear code in the numerous languages that implement it "properly" and because it generates an expression, sometimes it is the only way to quickfix something. I used quotes because while the PHP designers did make the asinine choice to make its ternary operator left-associative, the fact is well-documented.

The ternary operator is evaluated from left to right. So if you don't group the expressions properly, you will get an unexpected result.

PHP's advice is [docs]:

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.

Your code actually is evaluated as:

(
    (
        (
            $province == 6 ? "city-1" : $province == 7
        ) ? "city-2" : 
        $province == 8
    ) ? "city-3" : $province == 30
) ? "city-4" : "out of borders";

where it should be

$province == 6 ? "city-1" : (
    $province == 7 ? "city-2" : (
        $province == 8 ? "city-3" : (
           $province == 30 ? "city-4" : "out of borders"
        )
    )
);

This code might look fine but someone will read it and they will need more time than they should to understand what this code is doing.


You would be better off with something like this:

$map = array( 6 = >'city-1', 
              7 => 'city-2', 
              8 => 'city-3', 
             30 => 'city-4');

$Myprovince = "out of borders";

if(array_key_exists($province, $map)) {
    $Myprovince = $map[$province];
}

Or as @Jonah mentioned in his comment:

$Myprovince = isset($map[$province]) ? $map[$province] : 'out of borders';
  • 34
Reply Report
    • To your edit, I believe that the other lines are the c statements for the previous lines. Notice, no semi-colons. It's pretty much just: ($province == 6) ? "city-1" : ($province == 7) ? "city-2" : ($province == 8) ? "city-3" : ($province == 30) ? "city-4" : "out of borders";

Don't abuse the ternary operator for that sort of thing. It makes debugging near impossible to follow. Why not do something like

switch($province) {
    case 6: $Myprovince = "city-1"; break;
    case 7: ...
}

or simply some chained if/then/else

if ($province == 6) {
     $Myprovince = "city-1";
} elseif ($province = ...) {
   ...
}
  • 17
Reply Report

Some people have suggested using a switch statement or an if/else statement. But I would use an array instead, to make it easier to maintain and easier to read:

$provinces = array (
    6 => 'city-1',
    7 => 'city-2',
    8 => 'city-3',
    30 => 'city-4'
);

// then you can call:

$Myprovince = isset($provinces[$province]) ? $provinces[$province] : 'out of borders';

Why?

The code will probably eventually be easier to manage. Maybe you'll want to add those province-to-city mappings from database one day.. etc.. That will be hard to maintain with a bunch of switch/case statements.

  • 12
Reply Report

I understand this is a question about PHP, but since this is just an educational exercise anyways I thought you might be interested in learning that Ruby and Javascript actually behave the way you expect.

Ruby:

ree-1.8.7-2012.02 :009 > def foo x
ree-1.8.7-2012.02 :010?>   x == 1 ? "city 1" : x == 2 ? "city 2" : "out of borders"
ree-1.8.7-2012.02 :011?>   end
 => nil
ree-1.8.7-2012.02 :012 > foo 1
 => "city 1"
ree-1.8.7-2012.02 :013 > foo 2
 => "city 2"
ree-1.8.7-2012.02 :014 > foo 3
 => "out of borders"

Javascript:

> function f(x) { return x == 1 ? "city 1" : x == 2 ? "city 2" : "out of borders"; }
undefined
> f(1)
"city 1"
> f(2)
"city 2"
> f(3)
"out of borders"
  • 5
Reply Report
    • shrug ... of course Ruby and Javascript already do it ... they are programming languages after all ^_^

Try with some more parenthesis :

$Myprovince = (
($province == 6) ? "city-1" :
(($province == 7) ? "city-2" :
(($province == 8) ? "city-3" :
(($province == 30) ? "city-4" : "out of borders"
))));

Your code has a problem with the ternary operator priority.

But I think you should really drop this operator and try to use a switch instead.

  • 3
Reply Report

Use switch instead. Ternary operators really shouldn't be used for more than single conditions, as they quickly become very difficult to understand.

switch ($province) {
    case 6:
        $Myprovince = 'city-1';
        break;
    case 7:
        $Myprovince = 'city-2';
        break;
    case 8:
        $Myprovince = 'city-3';
        break;
    case 30:
        $Myprovince = 'city-4';
        break;
    default:
        $Myprovince = 'out of borders';
}
  • 0
Reply Report

I got myself into the same problem today. The others already giving acceptable solutions. Mine just an emphasis to one liner ifs. More readable in my opinion.

if ($province == 6) $Myprovince = 'city-1';
elseif ($province == 7) $Myprovince = 'city-2';
elseif ($province == 8) $Myprovince = 'city-3';
elseif ($province == 30) $Myprovince = 'city-4';
else $Myprovince = 'out of borders';
  • 0
Reply Report

Warm tip !!!

This article is reproduced from Stack Exchange / Stack Overflow, please click

Trending Tags

Related Questions