Matt
Matt

Reputation: 7040

Switch evaluations

I recently got into an argument over how switch handles comparisons, and need help settling it.

If I write a switch such as:

switch ($x){
    case ($x > 5):
        echo "foo";
        break;
    case ($x < 5):
        echo "bar";
        break;
    default:
        echo "five";
        break;
}

Which if statement is it equivalent to? A or B?

// A

if ($x > 5) {
    echo "foo";
} elseif ($x < 5) {
    echo "bar";
} else {
    echo "five";
}

// B

if ($x == ($x > 5)) {
    echo "foo";
} elseif ($x == ($x < 5)) {
    echo "bar";
} else {
    echo "five";
}

Upvotes: 0

Views: 334

Answers (3)

DaveRandom
DaveRandom

Reputation: 88677

To everyone, let me clarify:

It is equivalent to B.

It is not "both", it is not sometimes its one, sometimes it is the other, it is always B. To understand why you sometimes see results that indicate that it might be A, you need to understand how type coercion works in PHP.

If you pass in a falsey value to the "argument" of switch and you use expressions in your cases that result in a boolean value, they will only match if your expression evaluates to FALSE.


switch is basically a huge if/elseif tree that performs loose comparisons (== instead of ===) between the value passed to switch (the left side of the expression) and the expression in the cases (the right side).

This can be proved quite nicely with a variation on your code:

$x = 0;

switch ($x) {
  case $x > -1: // This is TRUE, but 0 == FALSE so this won't match
    echo "case 1";
  case $x == -1: // This is FALSE, and 0 == FALSE so this will match
    echo "case 2";
}

And if we convert that to the two if/elseif trees:

A:

$x = 0;

if ($x > -1) {
  // It matches here
  echo "case 1";
} else if ($x == -1) {
  // and not here
  echo "case 2";
}

B:

$x = 0;

if ($x == ($x > -1)) {
  // It doesn't match here
  echo "case 1";
} else if ($x == ($x == -1)) {
  // ..but here instead
  echo "case 2";
}

Upvotes: 5

Oussama Jilal
Oussama Jilal

Reputation: 7739

That switch case is equivalent to B

Edit :

If we take for example that $x is equal to 0 :

$x > 5 will evaluate to false (and 0 evaluates to false too), so the first if will print bar, but the second one will print foo. The switch will be transformed to something like this :

switch ($x){
    case false:
        echo "foo";
        break;
    case true:
        echo "bar";
        break;
    default:
        echo "five";
        break;
}

and that will print foo (same as B)

Edit 2 :

I tried it so that gave me :

with $x = 0 => switch (foo), if A (bar), if B (foo)

with $x = 5 => switch (five), if A (five), if B (five)

with $x = 7 => switch (foo), if A (foo), if B (foo)

Upvotes: 2

Florent
Florent

Reputation: 12420

Your example is equivalent to B.

If you want to use comparison into your switch (and be equivalent to A), you could write this:

switch (true) { // Use true instead of $x
    case ($x > 5):
        echo "foo";
        break;
    case ($x < 5):
        echo "bar";
        break;
    default:
        echo "five";
        break;
}

Upvotes: 2

Related Questions