coding-standard icon indicating copy to clipboard operation
coding-standard copied to clipboard

[Feature] Consistent foreach style

Open dereuromark opened this issue 2 years ago • 2 comments

I see code like

foreach ($usecases as $usecase) :
    $usecase->setDirty('name', true);
    $usecasesTable->save($usecase);
endforeach;

in some of the projects.

I would like to auto fix this via sniffer to the cleaner version

foreach ($usecases as $usecase) {
    $usecase->setDirty('name', true);
    $usecasesTable->save($usecase);
}

Especially since the former cannot be properly used by modern IDEs as PHPStorm. Even latest version doesnt show the closing part to the opening.

Is there an easy way to add this without accidentally killing the code or levels of nesting? I checked existing sniffers and didnt find a matching one so far.

I wonder which other tokens might also be of the same type we can replace:

        T_ENDIF               => T_ENDIF,
        T_ENDFOR              => T_ENDFOR,
        T_ENDFOREACH          => T_ENDFOREACH,
        T_ENDWHILE            => T_ENDWHILE,
        T_ENDSWITCH           => T_ENDSWITCH,
        T_ENDDECLARE          => T_ENDDECLARE,

dereuromark avatar Nov 17 '23 15:11 dereuromark

I analyzed the phpcs tokens

<?php
        foreach ($usecases as $usecase) :
// T_WHITESPACE (216) code=392, line=42, column=1, length=8, level=2, conditions={"65":333,"199":310}, content=`        `
// T_FOREACH (217) code=297, line=42, column=9, length=7, parenthesis_opener=219, parenthesis_closer=225, parenthesis_owner=217, scope_condition=217, scope_opener=227, scope_closer=251, level=2, conditions={"65":333,"199":310}, content=`foreach`
// T_WHITESPACE (218) code=392, line=42, column=16, length=1, level=2, conditions={"65":333,"199":310}, content=` `
// T_OPEN_PARENTHESIS (219) code=PHPCS_T_OPEN_PARENTHESIS, line=42, column=17, length=1, parenthesis_opener=219, parenthesis_owner=217, parenthesis_closer=225, level=2, conditions={"65":333,"199":310}, content=`(`
// T_VARIABLE (220) code=266, line=42, column=18, length=9, nested_parenthesis={"219":225}, level=2, conditions={"65":333,"199":310}, content=`$usecases`
// T_WHITESPACE (221) code=392, line=42, column=27, length=1, nested_parenthesis={"219":225}, level=2, conditions={"65":333,"199":310}, content=` `
// T_AS (222) code=301, line=42, column=28, length=2, nested_parenthesis={"219":225}, level=2, conditions={"65":333,"199":310}, content=`as`
// T_WHITESPACE (223) code=392, line=42, column=30, length=1, nested_parenthesis={"219":225}, level=2, conditions={"65":333,"199":310}, content=` `
// T_VARIABLE (224) code=266, line=42, column=31, length=8, nested_parenthesis={"219":225}, level=2, conditions={"65":333,"199":310}, content=`$usecase`
// T_CLOSE_PARENTHESIS (225) code=PHPCS_T_CLOSE_PARENTHESIS, line=42, column=39, length=1, parenthesis_owner=217, parenthesis_opener=219, parenthesis_closer=225, level=2, conditions={"65":333,"199":310}, content=`)`
// T_WHITESPACE (226) code=392, line=42, column=40, length=1, level=2, conditions={"65":333,"199":310}, content=` `
// T_COLON (227) code=PHPCS_T_COLON, line=42, column=41, length=1, scope_condition=217, scope_opener=227, scope_closer=251, level=2, conditions={"65":333,"199":310}, content=`:`
// T_WHITESPACE (228) code=392, line=42, column=42, length=0, level=3, conditions={"65":333,"199":310,"217":297}, content=`\n`
            $usecase->setDirty('name', true);
// T_WHITESPACE (229) code=392, line=43, column=1, length=12, level=3, conditions={"65":333,"199":310,"217":297}, content=`            `
// T_VARIABLE (230) code=266, line=43, column=13, length=8, level=3, conditions={"65":333,"199":310,"217":297}, content=`$usecase`
// T_OBJECT_OPERATOR (231) code=384, line=43, column=21, length=2, level=3, conditions={"65":333,"199":310,"217":297}, content=`->`
// T_STRING (232) code=262, line=43, column=23, length=8, level=3, conditions={"65":333,"199":310,"217":297}, content=`setDirty`
// T_OPEN_PARENTHESIS (233) code=PHPCS_T_OPEN_PARENTHESIS, line=43, column=31, length=1, parenthesis_opener=233, parenthesis_closer=238, level=3, conditions={"65":333,"199":310,"217":297}, content=`(`
// T_CONSTANT_ENCAPSED_STRING (234) code=269, line=43, column=32, length=6, nested_parenthesis={"233":238}, level=3, conditions={"65":333,"199":310,"217":297}, content=`'name'`
// T_COMMA (235) code=PHPCS_T_COMMA, line=43, column=38, length=1, nested_parenthesis={"233":238}, level=3, conditions={"65":333,"199":310,"217":297}, content=`,`
// T_WHITESPACE (236) code=392, line=43, column=39, length=1, nested_parenthesis={"233":238}, level=3, conditions={"65":333,"199":310,"217":297}, content=` `
// T_TRUE (237) code=PHPCS_T_TRUE, line=43, column=40, length=4, nested_parenthesis={"233":238}, level=3, conditions={"65":333,"199":310,"217":297}, content=`true`
// T_CLOSE_PARENTHESIS (238) code=PHPCS_T_CLOSE_PARENTHESIS, line=43, column=44, length=1, parenthesis_opener=233, parenthesis_closer=238, level=3, conditions={"65":333,"199":310,"217":297}, content=`)`
// T_SEMICOLON (239) code=PHPCS_T_SEMICOLON, line=43, column=45, length=1, level=3, conditions={"65":333,"199":310,"217":297}, content=`;`
// T_WHITESPACE (240) code=392, line=43, column=46, length=0, level=3, conditions={"65":333,"199":310,"217":297}, content=`\n`
            $usecasesTable->save($usecase);
// T_WHITESPACE (241) code=392, line=44, column=1, length=12, level=3, conditions={"65":333,"199":310,"217":297}, content=`            `
// T_VARIABLE (242) code=266, line=44, column=13, length=14, level=3, conditions={"65":333,"199":310,"217":297}, content=`$usecasesTable`
// T_OBJECT_OPERATOR (243) code=384, line=44, column=27, length=2, level=3, conditions={"65":333,"199":310,"217":297}, content=`->`
// T_STRING (244) code=262, line=44, column=29, length=4, level=3, conditions={"65":333,"199":310,"217":297}, content=`save`
// T_OPEN_PARENTHESIS (245) code=PHPCS_T_OPEN_PARENTHESIS, line=44, column=33, length=1, parenthesis_opener=245, parenthesis_closer=247, level=3, conditions={"65":333,"199":310,"217":297}, content=`(`
// T_VARIABLE (246) code=266, line=44, column=34, length=8, nested_parenthesis={"245":247}, level=3, conditions={"65":333,"199":310,"217":297}, content=`$usecase`
// T_CLOSE_PARENTHESIS (247) code=PHPCS_T_CLOSE_PARENTHESIS, line=44, column=42, length=1, parenthesis_opener=245, parenthesis_closer=247, level=3, conditions={"65":333,"199":310,"217":297}, content=`)`
// T_SEMICOLON (248) code=PHPCS_T_SEMICOLON, line=44, column=43, length=1, level=3, conditions={"65":333,"199":310,"217":297}, content=`;`
// T_WHITESPACE (249) code=392, line=44, column=44, length=0, level=3, conditions={"65":333,"199":310,"217":297}, content=`\n`
        endforeach;
// T_WHITESPACE (250) code=392, line=45, column=1, length=8, level=3, conditions={"65":333,"199":310,"217":297}, content=`        `
// T_ENDFOREACH (251) code=298, line=45, column=9, length=10, scope_condition=217, scope_opener=227, scope_closer=251, level=2, conditions={"65":333,"199":310}, content=`endforeach`
// T_SEMICOLON (252) code=PHPCS_T_SEMICOLON, line=45, column=19, length=1, level=2, conditions={"65":333,"199":310}, content=`;`
// T_WHITESPACE (253) code=392, line=45, column=20, length=0, level=2, conditions={"65":333,"199":310}, content=`\n`

It seems we just have to sniff for the T_ENDFOREACH, go to the scope_opener index and replace both. Seems like it should work safely.

Any interest in a sniff for this in the community or maintainer group?

dereuromark avatar Nov 17 '23 17:11 dereuromark

I whipped sth up that seems to work fine already: https://github.com/php-collective/code-sniffer/pull/6

dereuromark avatar Nov 17 '23 22:11 dereuromark