PHP Type juggling and Non-Strict Comparison Issues Switch surprises


Example

Switch statements use non-strict comparison to determine matches. This can lead to some nasty surprises. For example, consider the following statement:

switch ($name) {
    case 'input 1':
        $mode = 'output_1';
        break;
    case 'input 2':
        $mode = 'output_2';
        break;
    default:
        $mode = 'unknown';
        break;
}

This is a very simple statement, and works as expected when $name is a string, but can cause problems otherwise. For example, if $name is integer 0, then type-juggling will happen during the comparison. However, it's the literal value in the case statement that gets juggled, not the condition in the switch statement. The string "input 1" is converted to integer 0 which matches the input value of integer 0. The upshot of this is if you provide a value of integer 0, the first case always executes.

There are a few solutions to this problem:

Explicit casting

The value can be typecast to a string before comparison:

switch ((string)$name) {
...
}

Or a function known to return a string can also be used:

switch (strval($name)) {
...
}

Both of these methods ensure the value is of the same type as the value in the case statements.

Avoid switch

Using an if statement will provide us with control over how the comparison is done, allowing us to use strict comparison operators:

if ($name === "input 1") {
    $mode = "output_1";
} elseif ($name === "input 2") {
    $mode = "output_2";
} else {
    $mode = "unknown";
}