Cover Image
#laravel #tooling #php

Setting up php code style sniffer & fixer

~ 6 MINS READ
15th Mar 2022
Mohammed Omer By Mohammed Omer

Different people may have different coding styles. If you work on a team you don’t want everyone to code in their own style, this way the project will just get messy and unpleasant to read.

So it is crucial for teams to have a standard coding style. One way to achieve this on a php project is by using a tool such as php-cs-fixer .

Also, if you are the only developer working on a project, enforcing coding style will make your code cleaner and easier to read for your future self and in case someone took over the project.

Setup

Update: as of June 2022, Laravel has added a new package called pint that makes it super easy to setup code style fixer and sniffer, you can follow this guide to set it up.

To install php-cs-fixer on your project run:

composer require friendsofphp/php-cs-fixer --dev

Then create your coding style rules that you want to enforce on your codebase. To get started you can add a .php-cs-fixer.php file to your project root directory, you can copy the contents of this config file and tweak it to your liking.

<?php

use PhpCsFixer\Config;
use PhpCsFixer\Finder;

$rules = [
    'array_indentation' => true,
    'array_syntax' => ['syntax' => 'short'],
    'binary_operator_spaces' => [
        'default' => 'single_space',
        'operators' => ['=>' => null],
    ],
    'blank_line_after_namespace' => true,
    'blank_line_after_opening_tag' => true,
    'blank_line_before_statement' => [
        'statements' => ['return'],
    ],
    'braces' => true,
    'cast_spaces' => true,
    'class_attributes_separation' => [
        'elements' => [
            'const' => 'one',
            'method' => 'one',
            'property' => 'one',
            'trait_import' => 'none',
        ],
    ],
    'class_definition' => [
        'multi_line_extends_each_single_line' => true,
        'single_item_single_line' => true,
        'single_line' => true,
    ],
    'concat_space' => [
        'spacing' => 'none',
    ],
    'constant_case' => ['case' => 'lower'],
    'declare_equal_normalize' => true,
    'elseif' => true,
    'encoding' => true,
    'full_opening_tag' => true,
    'fully_qualified_strict_types' => true, // added by Shift
    'function_declaration' => true,
    'function_typehint_space' => true,
    'general_phpdoc_tag_rename' => true,
    'heredoc_to_nowdoc' => true,
    'include' => true,
    'increment_style' => ['style' => 'post'],
    'indentation_type' => true,
    'linebreak_after_opening_tag' => true,
    'line_ending' => true,
    'lowercase_cast' => true,
    'lowercase_keywords' => true,
    'lowercase_static_reference' => true, // added from Symfony
    'magic_method_casing' => true, // added from Symfony
    'magic_constant_casing' => true,
    'method_argument_space' => [
        'on_multiline' => 'ignore',
    ],
    'multiline_whitespace_before_semicolons' => [
        'strategy' => 'no_multi_line',
    ],
    'native_function_casing' => true,
    'no_alias_functions' => true,
    'no_extra_blank_lines' => [
        'tokens' => [
            'extra',
            'throw',
            'use',
        ],
    ],
    'no_blank_lines_after_class_opening' => true,
    'no_blank_lines_after_phpdoc' => true,
    'no_closing_tag' => true,
    'no_empty_phpdoc' => true,
    'no_empty_statement' => true,
    'no_leading_import_slash' => true,
    'no_leading_namespace_whitespace' => true,
    'no_mixed_echo_print' => [
        'use' => 'echo',
    ],
    'no_multiline_whitespace_around_double_arrow' => true,
    'no_short_bool_cast' => true,
    'no_singleline_whitespace_before_semicolons' => true,
    'no_spaces_after_function_name' => true,
    'no_spaces_around_offset' => [
        'positions' => ['inside', 'outside'],
    ],
    'no_spaces_inside_parenthesis' => true,
    'no_trailing_comma_in_list_call' => true,
    'no_trailing_comma_in_singleline_array' => true,
    'no_trailing_whitespace' => true,
    'no_trailing_whitespace_in_comment' => true,
    'no_unneeded_control_parentheses' => [
        'statements' => ['break', 'clone', 'continue', 'echo_print', 'return', 'switch_case', 'yield'],
    ],
    'no_unreachable_default_argument_value' => true,
    'no_useless_return' => true,
    'no_whitespace_before_comma_in_array' => true,
    'no_whitespace_in_blank_line' => true,
    'normalize_index_brace' => true,
    'not_operator_with_successor_space' => true,
    'object_operator_without_whitespace' => true,
    'ordered_imports' => ['sort_algorithm' => 'alpha'],
    'psr_autoloading' => true,
    'phpdoc_indent' => true,
    'phpdoc_inline_tag_normalizer' => true,
    'phpdoc_no_access' => true,
    'phpdoc_no_package' => true,
    'phpdoc_no_useless_inheritdoc' => true,
    'phpdoc_scalar' => true,
    'phpdoc_single_line_var_spacing' => true,
    'phpdoc_summary' => false,
    'phpdoc_to_comment' => false, // override to preserve user preference
    'phpdoc_tag_type' => true,
    'phpdoc_trim' => true,
    'phpdoc_types' => true,
    'phpdoc_var_without_name' => true,
    'self_accessor' => true,
    'short_scalar_cast' => true,
    'simplified_null_return' => false, // disabled as "risky"
    'single_blank_line_at_eof' => true,
    'single_blank_line_before_namespace' => true,
    'single_class_element_per_statement' => [
        'elements' => ['const', 'property'],
    ],
    'single_import_per_statement' => true,
    'single_line_after_imports' => true,
    'single_line_comment_style' => [
        'comment_types' => ['hash'],
    ],
    'single_quote' => true,
    'space_after_semicolon' => true,
    'standardize_not_equals' => true,
    'switch_case_semicolon_to_colon' => true,
    'switch_case_space' => true,
    'ternary_operator_spaces' => true,
    'trailing_comma_in_multiline' => ['elements' => ['arrays']],
    'trim_array_spaces' => true,
    'unary_operator_spaces' => true,
    'visibility_required' => [
        'elements' => ['method', 'property'],
    ],
    'whitespace_after_comma_in_array' => true,
];

$finder = Finder::create()
    ->in([
        __DIR__ . '/app',
        __DIR__ . '/config',
        __DIR__ . '/database',
        __DIR__ . '/resources',
        __DIR__ . '/routes',
        __DIR__ . '/tests',
    ])
    ->name('*.php')
    ->notName('*.blade.php')
    ->ignoreDotFiles(true)
    ->ignoreVCS(true);

return (new Config)
    ->setFinder($finder)
    ->setRules($rules)
    ->setRiskyAllowed(true)
    ->setUsingCache(true);

I usually create two composer scripts, one as a fixer and the other as a code sniffer, to have those scripts available in your project, add them to your composer.json file:

"scripts": {
        "format": [
                "vendor/bin/php-cs-fixer fix --show-progress=dots"
        ],
        "sniff": [
                "vendor/bin/php-cs-fixer fix --dry-run --show-progress=dots"
        ],
        ...
}

Then you can run composer format to fix coding style issues on your codebase, or composer sniff to see check if the coding style is correct and see which files break the coding style.

You can run the format command as a step on your ci pipeline to format your code or run the sniff command to test that the coding style is right.

A personal preference

I don’t like running the command manually before each commit, and I tried different vscode extensions but didn’t find the one that suits my needs, so I use a vscode extension called Run on save to format my php files after saving them.

After installing Run on save extension, go to your workspace settings file and add this command:

"emeraldwalk.runonsave": {
    "commands": [
        {
            "match": "\\.php$",
            "cmd": "vendor/bin/php-cs-fixer fix"
        },
    ]
}

Note that you have to add this to your workspace settings for every project that you want to enable php-cs-fixer on, and the project should have the package friendsofphp/php-cs-fixer installed.


If you liked this post consider sharing it :

You may also like

stopwatch6 MINS 
cover
By Mohammed Omer | 15th Jan 2022
#laravel #testing
stopwatch4 MINS 
cover
By Mohammed Omer | 1st Dec 2021
#laravel #security #testing
stopwatch2 MINS 
cover
By Mohammed Omer | 27th Mar 2022
#laravel #productivity #tooling #shorts 🔥
stopwatch14 MINS 
cover
By Mohammed Omer | 22nd Jan 2022
#laravel #linux #nginx
stopwatch4 MINS 
cover
By Mohammed Omer | 21st Dec 2021
#laravel #performance
stopwatch3 MINS 
cover
By Mohammed Omer | 7th Dec 2021
#laravel #linux