Jeremy Logan
Jeremy Logan

Reputation: 47514

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?

Upvotes: 8

Views: 770

Answers (3)

Marc B
Marc B

Reputation: 360912

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.

Upvotes: 1

lonesomeday
lonesomeday

Reputation: 238115

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.

Upvotes: 4

Ry-
Ry-

Reputation: 225281

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.

Upvotes: 8

Related Questions