17

How can I make the switch respect data types ( is there a workaround better then if/else ) ?

  • $value = false; // should echo false
  • $value = null; // should echo null

    
    switch ($value) {
        case '0' :
            echo 'zero';
            break;
        case '' :
            echo 'empty';
            break;
        case null :
            echo 'null';
            break;
        case false :
            echo 'false';
            break;
        default :
            echo 'default';
            break;
    }
    
    

    Conclusion

  • Switch/case does loose comparison.
  • Solutions: switch with ifs or if/else

  • 5
    • 1
      By "not working" I mean: to respect or take somehow into account the value type
      – johnlemon
      Commented Apr 6, 2011 at 7:55
    • 1
      let's try that again, what are you expecting to happen?
      – Hamish
      Commented Apr 6, 2011 at 7:57
    • 1
      Oh come on, let's not go into semantics. If it's boolean false it should echo false.
      – johnlemon
      Commented Apr 6, 2011 at 7:58
    • 2
      You need to be explicit. In this case, the script is "working", it just doesn't do what you expect.
      – Hamish
      Commented Apr 6, 2011 at 8:00
    • @Hamish, We don't want loose comparisons. 'Nuff said, clear as water.
      – Pacerier
      Commented Mar 5, 2015 at 20:13

    5 Answers 5

    30
    switch (true) {
        case $value === '0' :
            echo 'zero';
            break;
        case $value === '' :
            echo 'empty';
            break;
        case $value === null :
            echo 'null';
            break;
        case $value === false :
            echo 'false';
            break;
        default :
            echo 'default';
            break;
    }
    

    I think, it's more readable than a if-elseif-chain like given below:

    if ($value === '0') {
      echo 'zero';
    } else if ($value === '') {
      echo 'empty';
    } else if ($value === null) {
      echo 'null';
    } else if ($value === false) {
      echo 'false';
    } else {
      echo 'default';
    }
    
    13
    • 2
      Wouldn't agree on the readability part (one extra level of indention, same number of lines (if you format the if/else nicer than @nicola did) and a more direct way of expressing what you do to the next why that reads that (wtf factor @switch(true) for a second). But I'm nitpicking. +1
      – edorian
      Commented Apr 6, 2011 at 8:10
    • 1
      hey crunch, what a good hack huh, good thinking, enlightened me about how 'switch' actually operates
      – nicola
      Commented Apr 6, 2011 at 8:12
    • 2
      @edorian: Hmm... I replaced the "far more readable" with "I think, its more readable" ;) But I still think, its cleaner for more than (lets say) 3 oder 4 cases. With switch(true) every case statement is evaluated into something like true == ($statement). I thought, it was obvious.
      – KingCrunch
      Commented Apr 6, 2011 at 8:17
    • 1
      and more, i hate using 'switch' because if we miss a 'break;' then everything crashes
      – nicola
      Commented Apr 6, 2011 at 8:17
    • 2
      switch(true) is a desperately bad construct
      – DevDonkey
      Commented Oct 1, 2015 at 14:18
    5

    i believe you can try if-then to facilitate the use of '===' instead:

    <?php
    $value = 0;
    
    if ($value==="") {
      echo "blank (string)";
    }
    else
    if ($value==="0") {
      echo "zero (string)";
    }
    else
    if ($value===false) {
      echo "false (boolean)";
    }
    else
    if ($value===null) {
      echo "null (object)";
    }
    else
    if ($value===0) {
      echo "zero (number)";
    }
    else {
      echo "other";
    }
    ?>
    
    1
    • Well, several years old answer :) But anyway: When I read the left most column -- thats how I track down code the fast way -- I see several ifs. It's pretty easy to miss the else, that makes the if to an elseif, and therefore I see several independent conditions at first, instead of a chain. I wouldn't recommened this notation.
      – KingCrunch
      Commented Mar 7, 2015 at 14:53
    3

    in php.net manual it is a

    note: Note that switch/case does loose comparision.

    "loose comparison" means that switch won't check the type. 
     switch will only compare values:
    

    <?php 
    if('a string' == 0) echo 'a string is 0' . PHP_EOL;
    if('a string' === 0) echo 'but you will never see this' . PHP_EOL;
    switch(0){
        case 'a string': echo 'a string' . PHP_EOL;
        case 'another string': echo 'another string' . PHP_EOL;
    }
    
    if('a string' == true) echo 'a string is TRUE' . PHP_EOL;
    if('a string' === true) echo 'but you will never see this' . PHP_EOL;
    switch(true){
        case 'a string': echo 'a string' . PHP_EOL;
        case 'another string': echo 'another string' . PHP_EOL;
    }
    ?>
    
    will output:
    a string is 0
    a string
    another string
    a string is TRUE
    a string
    another string
    
    1

    another option, depending on what you like to look at:

    switch($foo ?: strtoupper(gettype($foo))){
        case 'bar':
        case 'bork':
            echo $foo;
            break;
    
        case 'NULL': // $foo === null
            echo 'null';
            break;
    
        case 'INTEGER': // $foo === 0
            echo 'zero';
            break;
    
        case 'ARRAY': // $foo === array()
            echo 'array';
            break;
    
        case 'STRING': // $foo === ''
            echo 'empty';
            break;
    
        case 'BOOLEAN': // $foo === false
            echo 'false';
            break;
    
        default:
            echo $foo;
            break;
    }
    

    depending on your data, you could include an underscore for added clarity, like '_NULL', but it's not as clean IMO.

    personally, I concur with the accepted answer for something like a quick null check:

    case $foo === null:
    
    2
    • I really like your solution. Can you elaborate on the $foo ?: strtoupper(gettype($foo)) part – specifically that ?: operator? I'm thinking just strtoupper(gettype($foo)) should be enough, but that's only because I don't know what the ?: operator does. … +1 for not putting true in the switch-statement (and actually switching on the data type)! :D
      – Matt
      Commented Nov 24, 2020 at 22:35
    • ?: is the Ternary operator in PHP. It's a shorthand if/then statement. like $x = (($a > $b) ? $a : $b); PHP let's you omit the "true" condition like: $x = $a ?: $b; so it checks if $a evaluates to true, if so, choose $a otherwise choose $b. so in the above switch, it uses the value of $foo unless it is false. and then the below are the "false" data types it evaluates to. (I would not code this professionally. if you're at this point, something should probably be simplified farther up stream to avoid bugs.) Commented Dec 5, 2020 at 7:29
    0

    Bare in mind that you're asking PHP to juggle types.

    If you see the PHP type comparison table you'll see that, for example, null and '' are loosly equivalent, ie null == ''.

    1
    • 2
      Yes, he's asking how to ask PHP not to juggle types.
      – Pacerier
      Commented Mar 5, 2015 at 20:13

    Not the answer you're looking for? Browse other questions tagged or ask your own question.