views:

62

answers:

4

I was looking to see if it's possible to set multiple variables with one ternary operator. I google'd a bit, but didn't come up with anything. I started testing a few ideas, and found something close -- but also getting some strange behavior; any ideas as to what's going on? And, is it possible to set more than one var in a single ternary operation? If so, is there a proper way of doing it?

$i=9;
($i==9)?($w=3|$r=2):($w=7|$r=1);
echo 'w= '.$w.' r= '.$r;//w= 3 r= 2


$i=9;
($i==9)?($w=4|$r=2):($w=7|$r=1);
echo 'w= '.$w.' r= '.$r;//w= 6 r= 2


$i=9;
($i==9)?($w=3|$r=7):($w=7|$r=1);
echo 'w= '.$w.' r= '.$r;//w= 7 r= 7


$i=444;
($i==9)?($w=4|$r=2):($w=7|$r=1);
echo 'w= '.$w.' r= '.$r;//w= 7 r= 1


$i=444;
($i==9)?($w=4|$r=2):($w=1|$r=1);
echo 'w= '.$w.' r= '.$r;//w= 1 r= 1 

Thanks...


Edit:

I did a little more testing, and found that this works correctly:

    ($i==9)?($w=4 AND $r=7):($w=7 AND $r=1);

however, I'm not sure if this is correct. And I'm curious as to what's going on in the first example.

+3  A: 

The OR operator is shortcutting the second assignments you're making within the expressions of your ternary. So the second assignment isn't getting made if the first evaluates to non zero.

If you switch to an AND statment (or &&) the second assignment in the expression is still dependant on the first: if the first evaluates to 0 (i.e. false), then the second half of the AND is not evaluated. That's probably a more difficult one to debug than the first, since it's probably rare that the first value will be zero. It may never be, and this will always work... until that one day...

The ternary operator is just shorthand for if...else... with single expressions rather than multiple statements. If you want multiple, independent assignments I highly recommend going with standard if...else... Easier to read all around.

Chadwick
A: 

You are missing a pipe character to form an OR clause:

($i==9)?($w=3|$r=2):($w=7|$r=1);

It should be:

($i == 9) ? ($w = 3 || $r = 2) : ($w = 7 || $r = 1);

And yes as can be seen you have more than one variable $w and $r used there.

Sarfraz
+4  A: 

As Chadwick has explained, using the AND or OR logical operators will not work the way you want them to:

$i = 0; $w = 0; $r = 0;
($i==9) ? ($w=4 AND $r=7) : ($w=7 AND $r=1);
echo "w = $w, r = $r\n";
// w = 7, r = 1

$i = 0; $w = 0; $r = 0;
($i==9) ? ($w=0 AND $r=7) : ($w=0 AND $r=1);
echo "w = $w, r = $r\n";
// w = 0, r = 0

However, if you really want to make multiple assignments in one statement, you can use the list construct:

$i = 0; $w = 0; $r = 0;
($i==9) ?
    (list($w, $r) = array(4, 7)) :
    (list($w, $r) = array(7, 1));
echo "w = $w, r = $r\n";
// w = 7, r = 1

$i = 0; $w = 0; $r = 0;
($i==9) ?
    (list($w, $r) = array(0, 7)) :
    (list($w, $r) = array(0, 1));
echo "w = $w, r = $r\n";
// w = 0, r = 1
Mike
+3  A: 

I am going to try an explain why your current code behaves like it behaves. First thing to know: | is the bitwise-or operator. Second thing to know: | has a higher operator precendance than = and therefore is executed first.

So, let's have a look at the first code: $w=3|$r=2. According to operator precedence this code may be written this way: $w=(3|$r=2). So $r get's set correctly and then $w=3|2 is performed. 3 in the dual system is 11 and 2 is 10.

  11
| 10
====
  11

So the result is correct.

Now, let's look at the second code:

$w=4|$r=2 is same as $w=(4|$r=2). $r is set correctly, then $w=4|2 is performed. 4 is 100 in dual system, 2 is 010:

  100
| 010
=====
  110

And 110 in the decimal system is 6!

So, now you know there the wrong values come from, now let's find a solution:

Using && here is discouraged, because if the first value was set to 0 the second wouldn't be set at all. Furthermore it has wrong operator precedence: $w=1&&$r=2 is same as $w=(1&&$r=2). So $w would always be assigned either true or false.

One possible solution would be to use the xor operator. This operator requires both sides to be executed and it has the perfect precendance:

$i == 9 ? ($w = 1 xor $r = 2) : ($w = 2 xor $r = 3);

But, you may imagine, this is hard to read, so better not use it...

nikic
+1 thanks for the excellent explanation. I read that the single pipe was a bitwise operator, but didn't know what it did. Interesting stuff. Thanks again!
stormdrain
+1 for good explanation of the issue.
Mike