Fix indentation of PHP code files with php-cs-fixer

12k views Asked by At

I have several hundreds of horribly indented PHP files with mixed tabs and spaces (and even mixed line endings, I suppose) I would like to fix them with php-cs-fixer v2+.

I have configured php-cs-fixer to my needs, and the code is scrubbed accordingly - except the indentation. I have tried a minimal configuration, like shown bellow, to pin down the problem. But I cannot get the indentation fixer straight:

return PhpCsFixer\Config::create()
    ->setRules([
        '@PSR2' => true,
        'indentation_type' => true,
        'braces' => ['position_after_functions_and_oop_constructs' => 'same'],
    ])
    ->setIndent("\t")
    ->setLineEnding("\r\n")

Currently, I run this on my Windows box using the following command (here for a single file):

php-cs-fixer.bat fix new_user.php --config /full/windowspath/to/php_cs.dist

Just in case, the generated php_cs.cache (which contains the actually applied rules in JSON) file looks like this:

{
    "php": "5.6.31",
    "version": "2.6.0:v2.6.0#5642a36a60c11cdd01488d192541a89bb44a4abf",
    "rules": {
        "blank_line_after_namespace": true,
        "braces": {
            "position_after_functions_and_oop_constructs": "same"
        },
        "class_definition": true,
        "elseif": true,
        "function_declaration": true,
        "indentation_type": true,
        "line_ending": true,
        "lowercase_constants": true,
        "lowercase_keywords": true,
        "method_argument_space": {
            "ensure_fully_multiline": true
        },
        "no_break_comment": true,
        "no_closing_tag": true,
        "no_spaces_after_function_name": true,
        "no_spaces_inside_parenthesis": true,
        "no_trailing_whitespace": true,
        "no_trailing_whitespace_in_comment": true,
        "single_blank_line_at_eof": true,
        "single_class_element_per_statement": {
            "elements": ["property"]
        },
        "single_import_per_statement": true,
        "single_line_after_imports": true,
        "switch_case_semicolon_to_colon": true,
        "switch_case_space": true,
        "visibility_required": true,
        "encoding": true,
        "full_opening_tag": true
    },
    "hashes": {
        "new_students.org_.php": -151826318
    }
}

And here is some badly indented sample file content.

<?php
session_start();

  include 'connect.php';
include 'functions.php';    

$test= "abc";
    $additional_studs = "";
    if (date('m') == 12 and $term='SP') {
        $yr_suffix = date('y') + 1;
    } else {
        $yr_suffix = date('y');
    }


    function dup_stud($id, $conn)
    {//...
}

$i = 0;

I am most annoyed be lines like $test="abc"; & include 'connect.php'; with one or more leading tabs/spaces that do not get properly indented.

I am open to alternative approaches. Others must have faced formatting issues like this before.

I have also tried NetBeans, which happens to format the source beautifully, but it is tedious to open each file manually and apply the source formatting via shortcut.

4

There are 4 answers

2
Jan Tojnar On BEST ANSWER

You should use braces fixer to force indentation.

The body of each structure MUST be enclosed by braces. Braces should be properly placed. Body of braces should be properly indented.

indentation_type simply enforces consistency.

But since both the fixers are already included in @PSR2 so the code should be fixed correctly.

See the relevant sections in the README.


Using your code php-cs-fixer 2.6 produces the following code

<?php
$test= "abc";
    $additional_studs = "";
    if (date('m') == 12 and $term='SP') {
        $yr_suffix = date('y') + 1;
    } else {
        $yr_suffix = date('y');
    }


    function dup_stud($id, $conn)
    {//...
    }

$i = 0;

where the indentation is only partly fixed.

I reduced it to the code below

<?php
echo "a";
    echo "b";
echo "c";

It looks like a bug in php-cs-fixer.

0
Ira Baxter On

OP says

I am open to alternative approaches. Others must have faced formatting issues like this before.

Our PHP Formatter will indent files nicely. See OP's "badly indented" sample processed by the PHP Formatter:

C:\>DMSFormat PHP~v7 \temp\test.php
PHP~v7 PrettyPrinter Version 1.3.17
Copyright (C) 2004-2016 Semantic Designs, Inc; All Rights Reserved; SD Confidential
Powered by DMS (R) Software Reengineering Toolkit
DMS_PHP~v7_INPUT_ENCODING=ISO-8859-1
DMS_PHP~v7_OUTPUT_ENCODING=ISO-8859-1
Parsing \temp\test.php [encoding ISO-8859-1 +CRLF +LF +CR +NEL +1 /^I]


<?php
include 'connect.php';
include 'functions.php';
$test="abc";
$additional_studs="";
if (date('m') == 12 and $term='SP') {
  $yr_suffix=date('y')+1;
}
else {
  $yr_suffix=date('y');
}

function dup_stud($id,$conn) { //...
}
$i=0;

(I had to add

<?php

to the start of the file to make it legal.)

This example was run from a file to the console. You can also do one file to one file, or run an entire list of files using a project file [this is probably what OP wants].

The PHP formatter uses a real PHP parser to process the source text and build an abstract syntax tree, and a special prettyprinter to print the AST back to nicely formatted text. It can't screw up the file.

3
wp78de On

I will answer my own question based on the findings that led me to a resolution.

While the formatting basically worked, the catch for me was the indentation. If there were some leading spaces or tabs, certain lines kept sticking out after the fix.

Since neither php-cs-fixer nor phpcbf was able to fix the indentation properly I took desperate measures and trimmed every leading whitespace from each line as preparatory step with sed in a script like this:

sed "s/^[ \t]*//" -i test.php

Then I processed some prepped files again with php-cs-fixer and phpcbf to find out which one does a better job formatting the files according to PSR-2. It's shameful, but both fixers failed again - now showing some different shortcomings (i.e. bugs). To cut a long story short, I finally learnt that coupling the two tools leads to properly formatted code files. What a mess.

So, after sed, I run phpcbf

phpcbf --standard="PSR2" test.php

followed by

php-cs-fixer fix test.php --rules=@PSR2

And all the sudden I have beautifully PSR-2 formatted PHP files. Not the most efficient way, but it does the job.

Some additional comments:

  • If you would like to apply additional fixer rules, I would suggest to do this in a 4th step using a different, more complete php_cs configuration from a PSR-2 baseline formatting (because, you know, there are more fixer issues..).
  • I suggest to use 4 spaces as indent, as required by PSR-2. According to my experience things get even more complicated if you insist to have tabs.
  • The described procedure wouldn't be necessary if php-cs-fixer and phpcbf would not have so many issues. I will report them one after another, and hopefully, in the future the same can be achieved in one go.
0
Pati K On

About alternative options. I also had a problem with automatic code formatting in Visual Studio Code. I tried some formatters but only phpfmt solved my problem with indentation and putting braces in the right place. It also has many customization options but I didn't test them, since they weren't needed.