Stacking Multiple Ternary Operators in PHP
Solution 1
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")))
);
Solution 2
The ternary operator is evaluated from left to right. So if you don't group the expressions properly, you will get an unexpected result.
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';
Solution 3
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 = ...) {
...
}
Solution 4
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.
Solution 5
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"
Related videos on Youtube
Comments
-
Mac Taylor over 2 years
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 ofswitch/if
because I want to experiment and see how it would be done.What's the problem with this code?
-
Jim about 13 yearsIs there a reason you don't want to just use
if / elseif
orswitch
? -
Czechnology about 13 yearsYou'd need many more brackets for this to work. User a
switch
as Marc suggested. -
Jonah about 13 years@Mac: you're driving me crazy with curiosity :D ! Why do you need to use ternary operators?
-
Mark Baker about 13 yearsUsing 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?
-
Mac Taylor about 13 yearsim using ternary operators because of my own curiosity nothing else , i know its not good for complex conditions statement but in learning and testing php details i need to correct it :D
-
Jim about 13 yearsCheck your answers below: stackoverflow.com/questions/5235632/5235721#5235721
-
Jonah about 13 yearsWow, this is the most heavily voted-on bunch of comments and answers I've ever seen.
-
Lightness Races in Orbit about 13 years@Jonah: You must be new here.
-
Joe Phillips about 13 years@Mac at least tell us you're not using this in real code so we can feel better about it
-
Mac Taylor about 13 yearsgod , please , I WOULD NOT USE THIS Method in a live script , never ever , are you better now ? just curious how to use it :D
-
Shanimal about 12 yearswow. If there's a legitimate reason the code is not working as expected, then by all means point it out. "answers" questioning the motives of arbitrary examples are far more inappropriate than the motive of arbitrary examples. +1 to codaddict and @arnorhs for thoughtful additions.
-
Curt about 2 yearsIt's very unfortunate that PHP got the precedence wrong for ?: when it's a common and useful construct in C that is EASY to read and use, and which every other language that borrowed it got right. I'm here because PHP 8 has been changed so it CRASHES without the unnecessary parens and BROKE my web site when I upgraded to it. For shame. Was my site already broken? NO, it was working fine -- and if they'd simply fixed the precedence they also would have fixed my inconsequential "bug".
-
-
Mac Taylor about 13 yearsdidn't i mentioned that i insist in using tenary operators because some reasons ?
-
Felix Kling about 13 years@Mac Taylor: No you didn't. What is the reason? Obscurity?
-
Marc B about 13 years@Felix: perhaps debugging masochism?
-
Jonah about 13 yearsMake it even shorter with this:
$Myprovince = isset($map[$province]) ? $map[$province] : 'out of borders';
;-) -
Marc B about 13 yearsshudder I'd +1 your bravery for typing that out, but can't bring myself to "endorse" such a hideous thing...
-
Felix Kling about 13 years@Jonah: True :D I guess I wanted to go away from the ternary operator as far as possible ;)
-
Zeta Two about 13 yearsThis is indeed the "correct" way to do it. I would never ever attempt anything like this though.
-
Mark Baker about 13 yearsDefinitely warrants a +1 for persevering
-
Phoenix about 13 yearsTo 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";
-
John Parker about 13 years+1 Correct (yet horrifying). Still, you were just satisfying the OPs freakish whim to do the wrong thing. (Nothing to see here, move along please.) :-)
-
Mac Taylor about 13 yearsthanks man this is what i looking for .. i don't even know why they trying to suggest other ways !
-
John Parker about 13 years@Mac If you really think this is the best solution (despite the disclaimer made by @codeaddict), then all I can hope is that I never have to maintain any of your code in the future. A
switch
statement or array lookup is the sane way to go if you care about code legibility/maintainability. -
Jim about 13 yearsThey suggested other ways because you never said you wanted this done via
ternary
in your original post. -
Felix Kling about 13 years@Phoenix: Yeah I noticed it and fixed it. I got very confused by all this
?
and:
;) -
Mac Taylor about 13 yearsI said so . but a bad mistake happened , i created two topics mistakenly , and in that topic i said that "don't suggest other ways"... and lovely to see that , the topic is getting more and more negative points .
-
Felix Kling about 13 years@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! -
Felix Kling about 13 years@Mac Taylor: For more information, have a look at the documentation: php.net/manual/en/…
-
Lajos Mészáros about 10 yearsPHP's the only language of the ternary operator capable languages, that works differently from other languages' implementation: phpsadness.com/sad/30
-
Hi-Angel about 9 yearsI'm wonder, is there a documented reason for the author's code to not work? From what I know it looks to me like a PHP bug.
-
Thanh Trung almost 9 yearsI would do like you. Definitely the best answer!
-
Steven Lu almost 9 yearsI 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.
-
Emanuil Rusev over 8 yearsThe big benefit of the ternary over these is that it allows having a single variable assignment.
-
dreftymac over 7 yearsshrug ... of course Ruby and Javascript already do it ... they are programming languages after all ^_^
-
Adam Copley almost 7 yearsdefinitely the best solution to this problem
-
Fandi Susanto over 4 yearsThis one is good. Be careful of "out of memory" problem though.
-
Vladimir Ch over 3 yearsor
$Myprovince = $map[$province] ?? 'out of borders';
-
mickmackusa about 3 yearsSwitches are ugly, yes, but better would be a lookup array with a
isset()
check -- easy and clean. -
Barmar over 2 yearsNote that PHP 8 has disabled nested ternaries without explicit parentheses.