Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic InlineControlStructureSniff can create parse error when case/if/elseif/else have mixed brace and braceless definitions #879

Closed
madflow opened this issue Jan 28, 2016 · 6 comments

Comments

@madflow
Copy link

madflow commented Jan 28, 2016

Hi,

bin/phpcbf --version
PHP_CodeSniffer version 2.5.1 (stable) by Squiz (http://www.squiz.net)

I tried to clean the following function:

bin/phpcbf --standard=PSR2 test.php

<?php
// test.php

function sth($data, $type)
{
    switch ($type) {
    case Format::NONE:
        return true;
    case Format::DATE:
    case Format::TIME:
    case Format::DATETIME:
    case Format::DATETIMEU:
        if (empty($data)) { return true; 
        }
        elseif (!is_object($data)) {
            $datetime = date_create($data);
            return ($datetime!==false);
        }
        elseif ($data instanceof \DateTime) 
        return true;
    else {
        throw new FormatException('Unknown datetime object: ' . get_class($data));
    }
            break;
    default:
        throw new FormatException('Unknown format: ' . print_r($type, true));
    }
}

This results in:

Processing test.php [PHP => 199 tokens in 26 lines]... DONE in 8ms (12 fixable violations)
=> Fixing file: 0/12 violations remaining [made 6 passes]... DONE in 51ms
Patched 1 file
Time: 134ms; Memory: 4.75Mb

➜ /tmp php -l test.php
PHP Parse error: syntax error, unexpected 'else' (T_ELSE) in test.php on line 20
Errors parsing test.php

I did the same with

PHP_CodeSniffer version 2.3.4 (stable) by Squiz (http://www.squiz.net)

=> this does not create a parse error.

@aik099
Copy link
Contributor

aik099 commented Jan 28, 2016

Yes, there seem to be a syntax error. Maybe code you're testing (that file specifically) is loaded via autoloader somehow?

If that is, then it's 2nd occasion, when including Composer auto-loader inside CLI.php of PHP_CodeSniffer has backfired.

@gsherwood
Copy link
Member

Maybe code you're testing (that file specifically) is loaded via autoloader somehow?

I think the report is actually saying that PHPCBF fixed the file incorrectly. This doesn't have anything to do with autoloading.

@gsherwood
Copy link
Member

In your code, the elseif ($data instanceof \DateTime) doesn't contain any braces while the rest of the IF statement does. I think this is where PHPCS is being tripped up, but only when inside a case statement.

@gsherwood
Copy link
Member

I figured out the problem, although it is the very definition of an edge case, and I have no idea how to solve it.

With this code snippet:

<?php
switch ($type) {
    case 1:  // line 3
        if ($foo) {
            return true;
        } elseif ($baz) // line 6
            return true; // line 7
        else {
            echo 'else';
        }
    break;
}

The return on line 7 is being assigned as the closer for the case on line 3 because the elseif on line 6 doesn't have any braces and so PHPCS walks back to the ( after the elseif and continues processing from there.

I can't find a more simple test case than this as it seems the combination of the mixed braces/non-braces and the use of a case statement is required.

@gsherwood gsherwood changed the title PHP Parse error: syntax error, unexpected 'else' (T_ELSE) Generic InlineControlStructureSniff can create parse error when case/if/elseif/else have mixed brace and braceless definitions Jan 29, 2016
gsherwood added a commit that referenced this issue Jan 29, 2016
… error when case/if/elseif/else have mixed brace and braceless definitions
@gsherwood
Copy link
Member

I've fixed this case without breaking any other tests by adding an exception for it in the tokenizer. Your code is now fixed like this:

<?php
// test.php

function sth($data, $type)
{
    switch ($type) {
        case Format::NONE:
            return true;
        case Format::DATE:
        case Format::TIME:
        case Format::DATETIME:
        case Format::DATETIMEU:
            if (empty($data)) {
                return true;
            } elseif (!is_object($data)) {
                $datetime = date_create($data);
                return ($datetime!==false);
            } elseif ($data instanceof \DateTime) {
                return true;
            } else {
                throw new FormatException('Unknown datetime object: ' . get_class($data));
            }
            break;
        default:
            throw new FormatException('Unknown format: ' . print_r($type, true));
    }
}

Thanks for reporting.

@madflow
Copy link
Author

madflow commented Jan 29, 2016

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants