Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP allowing invalid code in switch statements

I'm having some trouble understanding why the following doesn't result in a compiler error in 5.3.3 (errored-out correctly on my coworkers 5.2.5):

<?php
    echo "starting\n";

    switch(1) {
        case 2:
            echo "two\n";
            break;
        defalut:        // note the misspelling
            echo "deflaut\n";
    }

    echo "ending\n";

Instead of giving me a compiler error (or even a warning) it just gives this:

starting
ending

However, if I use it in an if-statement it gives me what I'd expect:

<?php
    if (1 == deflaut)
        echo "deflaut2\n";

gives:

PHP Notice:  Use of undefined constant deflaut - assumed 'deflaut' in ...

Why is this? Is there a setting somewhere I can disable to tell it to be strict about this sort of thing?

like image 860
Jeremy Logan Avatar asked Jul 08 '11 20:07

Jeremy Logan


3 Answers

It could possibly be interpreting it as just another label (which makes sense, given that technically default is a label and case could be interpreted as a special kind of label too) that could be used with goto. Try a goto and find out. I would, but I don't have PHP 5.3.3, sorry.

like image 124
Ry- Avatar answered Nov 06 '22 01:11

Ry-


The problem is that your code isn't doing what you think. A case block only ends when the next case block occurs, or when default: is found, or when the closing } is reached. This means that defalut is part of the case 2: block. So it is never even interpreted.

However, it doesn't even fire a syntax error (not even if you do switch (2). This is because the goto operator was introduced in PHP 5.3. The syntax word: at the beginning of a PHP statement is now a target accessible via goto. So goto defalut; can be used to go to the label.

(Actually, it can't, because of a restriction on targets inside switch blocks to avoid infinite loops, but this should illustrate the point...)

You can make it force an error by doing case defalut, when the error that you expect is found.

like image 4
lonesomeday Avatar answered Nov 06 '22 00:11

lonesomeday


Interesting, on my 5.3.2, this does fail IF there is NO other case statement above the mispelled default.

This dies with a "T_UNEXPECTED_STRING" syntax error:

switch (1) {
   defalut:
       echo "this should never come out";
       break;
   default:
       echo "default matched properly"
}

This one works:

switch (1) {
   case 2:
        echo "2\n";
        break;
   defalut:
        echo "this should never come out";
        break;
   default:
        echo "the default value\n";
}

It would appear you've found a bug in the PHP parser. Wouldn't consider a serious bug, but a bug nonetheless.

like image 1
Marc B Avatar answered Nov 06 '22 01:11

Marc B