1

I have the following PHP (the server is running version 5.3.x) in a script which is giving me a result that I am having trouble understanding. The general idea of this code is that I have a "normal mode", and two maintenance modes. In the first maintenance mode, data is only evaluated and can be viewed by an admin but is not stored to the database. If I set $maintenance_mode_enabled = 2;, then the same "preview" output should be displayed but only SOME specific updates to the database should be processed. The reason I added the ==2 comparison is because I found the need for a third option after I had setup the true/false for the basic default maintenance mode. At any rate, I noticed 18 records on my last maintenance_mode_enabled = true; run that were partially updated during the process, just as though I had set maintenance_mode_enabled = 2;.

        $maintenance_mode_enabled = true;

        if ($maintenance_mode_enabled){
            echo "Case 0\n";
        }

        if (!$maintenance_mode_enabled){
            echo "Case 1\n";
        }

        if ($maintenance_mode_enabled == 2){
            echo "Case 2\n";
        }

The output I get is:

Case 0
Case 2

From what I understood, true (being boolean) is definitely not equal to 3. I am familiar with some oddities when comparing false, NULL and 0, but this problem with integers and TRUE is entirely new to me.

Any ideas as to why this isn't working? I realize that I can just as easily change $maintenance_mode_enabled to an integer instead of a bolean by default, and set it as either 0, 1 or 2 to get the desired results, but I really want to understand WHY this seems to defy logic.

bwright
  • 347
  • 1
  • 15

3 Answers3

4

The reason this happens is because you're comparing a boolean to an integer. As with many languages, at the core of the comparison function it's casting the second part of your comparison to a boolean. Any non-NULL, non-zero, non-empty or non-false value, in this case 2 is "true."

As the previous answer mentions I would change the code to use strict comparison. I would also change from three separate if-statements to one if-elseif statement:

if ($maintenance_mode_enabled === true) {
    // catches only true not > 0
    echo "Case 0\n";
} elseif ($maintenance_mode_enabled === false) {
    // catches only true not = 0
    echo "Case 1\n";
} elseif ((int)$maintenance_mode_enabled === 2) {
    echo "Case 2\n";
}

I recommend this change because maintenance mode can only have one value.

EDIT

I didn't realize true and 2 could coexist. You could do:

if ($maintenance_mode_enabled) {
    echo "Case 0\n";
    if (2 === (int)$maintenance_mode_enabled) {
        echo "Case 2\n";
    }
} else {
    echo "Case 1\n";
}
nmallare
  • 97
  • 5
  • With your code, doesn't `Case 0` NOT get printed if `$maintenance_mode_enabled` was set to 2? I want both the regular maintenance mode "display what would update without updating anything" (`Case 0`), and the "make only a few updates" (`Case 2`) maintenance mode to both run when `$maintenance_mode_enabled` is 2. – bwright Aug 19 '14 at 04:08
  • Is my updated answer sufficient? If so, can you make my answer as correct? – nmallare Aug 20 '14 at 18:45
  • The separate if statements need to remain separate for my purpose, since they all do different things through out the script. Your technical answer regarding the functionality of the comarison is correct though, so I did upvote you. – bwright Aug 21 '14 at 16:02
1

Use the === operator for true otherwise all non 0 / null / false will be true.

Use the === operator for false otherwise all equal to 0 / false / null will show as "false"

The following will output Case 0

<?php 
 $maintenance_mode_enabled = true;
 if ($maintenance_mode_enabled === true){
        // catches only true not just > 0
        echo "Case 0\n";
    }

    elseif (!$maintenance_mode_enabled === false){
        // catches only false not including = 0
        echo "Case 1\n";
    }
    elseif ($maintenance_mode_enabled == 2){
        echo "Case 2\n";
    }

?>
mseifert
  • 5,390
  • 9
  • 38
  • 100
  • The problem in your code is that `$maintenance_mode_enabled = true` will still cause `Case 2` to be outputted. The problem here is type casting (or type juggling), which I realized when re-examining the PHP docs: http://php.net/manual/en/language.operators.comparison.php – bwright Aug 19 '14 at 03:54
  • You are correct. I fixed the logic to output `Case 0` – mseifert Aug 19 '14 at 04:47
0

Oh, NOW I get it. It seems the problem here is that when I do the loose (==) comparison of a boolean with an integer, the type casting is converting the integer into a boolean, thus resulting in 2 being equal to true - since both are being tested as booleans. The solution is to use strict (===) comparison, so that both must be of the same type... i.e.: 2 (integer), is not exactly the same as true, since true is is of a different type - boolean.

bwright
  • 347
  • 1
  • 15
  • [`is_bool`](http://php.net/is_bool) and [`is_int`](http://php.net/is_int) and utilizing `elseif` trees would also be an option. In particular when using state variables for three distinct purposes, can help clarify the implied logic. – mario Aug 19 '14 at 03:57
  • @mario - true, though this is overkill for my purposes. Simply adding a third `=` to my `Case 2` comparison suffices. – bwright Aug 19 '14 at 03:59