Php-cs-fixer: PSR-12 Support

Created on 12 Aug 2019  ·  41Comments  ·  Source: FriendsOfPHP/PHP-CS-Fixer

PSR-12 just got approved.

I think PHP CS Fixer already supports almost all of its rules. The missing cases I could notice are the following:


3. Declare Statements, Namespace, and Import Statements

The header of a PHP file may consist of a number of different blocks. If present, each of the blocks below MUST be separated by a single blank line, and MUST NOT contain a blank line. Each block MUST be in the order listed below, although blocks that are not relevant may be omitted.

  • Opening <?php tag.
  • File-level docblock.
  • One or more declare statements.
  • The namespace declaration of the file.
  • One or more class-based use import statements.
  • One or more function-based use import statements.
  • One or more constant-based use import statements.
  • The remainder of the code in the file.

ordered_imports currently sorts imports without considering their type. We should add an option to sort by type first. We should also add an option (or dedicated rule) to add a separation line between each import group.


[In control structures, ]expressions in parentheses MAY be split across multiple lines, where each subsequent line is indented at least once. When doing so, the first condition MUST be on the next line. Boolean operators between conditions MUST always be at the beginning or at the end of the line, not a mix of both.

We need to create a fixer that could force boolean operators to always be at the same position with two options like e.g.:

  • position (beginning or end): choose whether the operators should be at the beginning or end of the lines;
  • when (always or mixed): whether the rule should always be applied or only when a mix of positions is found.

We also need to support the multiple lines part of the rule:

  • each subsequent line is indented at least once;
  • the first condition must be on the next line.

Anonymous Classes MUST follow the same guidelines and principles as closures in the above section.

You need to update class_definition to support adding a spacing before the parentheses in new class().

The opening brace [of an anonymous class] MAY be on the same line as the class keyword so long as the list of implements interfaces does not wrap. If the list of interfaces wraps, the brace MUST be placed on the line immediately following the last interface.

I think this is currently covered by the rule braces. Not sure if we should add a new option to it or create a new fixer.


TODO

  • [ ] support for ordering imports by type first
  • [ ] support for adding separation lines between import group
  • [ ] support for boolean operator position in control structure expression
  • [ ] support for indenting multiline control structure expressions
  • [ ] support for forcing first condition of multiline control structure expressions to be on next line
  • [ ] support for anonymous class opening brace in case implements list wraps
  • [ ] support for forcing blank line between import statement types (#3582)
  • [ ] support for adding a space before parentheses in new class()
  • [ ] @PSR12 ruleset (#4943)
kinfeature request kinmeta topiPSR-12

Most helpful comment

From #4568, perhaps PSR-12 should be the default configuration for v3.

All 41 comments

What about this - specifically the part about spaces between class/function/const imports. It this possible currently?

What about this - specifically the part about spaces between class/function/const imports. It this possible currently?

No, the newlines between different use types is not yet possible, however there is a longstanding issue (without PR) addressing it: #3582

_edit: I would like to see that being resolved as well as part of this meta-issue_

When doing so, the first condition MUST be on the next line.

Is this part already covered somewhere?

As to your boolean operator fixer: I'd like the fixer to be able to do both, depending on config (always_front, always_back, when_mixed_front, when_mixed_back). It was not clear from your suggestion if you meant this, or just let it do only one of the bullet-points.

@kbond Indeed, I updated my post with PR ref given by @dmvdbrugge.

@dmvdbrugge Actually even the _"each subsequent line is indented at least once"_ isn't supported currently. I updated my post to add the rules. As they both deal with whitespace, maybe we could implement them in a single fixer?

I also updated my suggestion for the boolean operator position fixer, hope it's better now :) Thanks!

From #4568, perhaps PSR-12 should be the default configuration for v3.

Any update on psr-12 support?

Nope, nobody gave it a try yet.

Perhaps it makes sense to create a branch that aggregates a @PSR12 rule set, so we can see where we are and what's missing?

We can create a @PSR12 ruleset indeed, even if it doesn't contain any specific rule yet. Though tracking progress regarding PSR-12 support is the exact purpose of the original post of this issue :)

A provisional rule set for PSR-12 is:

[
    '@PSR2' => true,
    'blank_line_after_opening_tag' => true,
    'compact_nullable_typehint' => true,
    'declare_equal_normalize' => ['space' => 'none'],
    'function_typehint_space' => true,
    'new_with_braces' => true,
    'no_empty_statement' => true,
    'no_leading_import_slash' => true,
    'no_leading_namespace_whitespace' => true,
    'no_whitespace_in_blank_line' => true,
    'return_type_declaration' => ['space_before' => 'none'],
    'single_trait_insert_per_statement' => true,
];

I think there are some minor incompatibilities with PSR2, so this is not quite right to include PSR2 (I haven't looked in enough detail to list them all), so that will need to be addressed. There are also various bits and pieces from the spec not covered by the rules I listed here, most of which are listed in the OP (I say most of which because I am not certain we have them all, but I also don't know of anything missing right now).


EDIT (5TH MARCH 2020):

```php
[
'@PSR2' => true,
'blank_line_after_opening_tag' => true,
'braces' => ['allow_single_line_closure' => true],
'compact_nullable_typehint' => true,
'concat_space' => ['spacing' => 'one'],
'declare_equal_normalize' => ['space' => 'none'],
'function_typehint_space' => true,
'new_with_braces' => true,
'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
'no_empty_statement' => true,
'no_leading_import_slash' => true,
'no_leading_namespace_whitespace' => true,
'no_whitespace_in_blank_line' => true,
'return_type_declaration' => ['space_before' => 'none'],
'single_trait_insert_per_statement' => true,
];

What about this https://github.com/KorvinSzanto/PHP-CS-Fixer/blob/feature/psr12/src/RuleSet.php#L60 ? Is this finished, abandoned or what?

That other ruleset seems to do a lot of stuff that PSR-12 doesn't actually mandate. For example, the PSR-12 spec says nothing about the ordering of imports. It only mandates formatting requirements and separation of the different types. It doesn't say each type of import must be alphabetically ordered. Also, that rule set you linked seems to have copied rules already in PSR2, twice.

[anonymous classes]

I think this is currently covered by the rule braces. Not sure if we should add a new option to it or create a new fixer.

when comparing PHP_CodeSniffer's PSR-12 support with PHP-CS-Fixer I also noticed that PSR-12 is underspecified with regards to anonymous classes in that it doesn't specify whether parentheses should be used after the new keyword when there are no constructor arguments.

Their sample in the spec doesn't use any.

PHP_CodeSniffer insists on there not being any.

PHP-CS-Fixer puts them there via the braces rule.

$instance = new class {
};

vs.

$instance = new class() {
};

@pilif I am for the parenthesis to make it consistent with every other class instantiation.

To be fair, chapter 4 says:

The term “class” refers to all classes, interfaces, and traits.
[...]
When instantiating a new class, parentheses MUST always be present even when there are no arguments passed to the constructor.

If you read this strictly, it should apply to anonymous classes too.

~the braces rule could be split up; taking the must have braces part to its own fixer; @ see https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues/823~

:+1: for allowing single line anonymous classes like we have allow_single_line_closure on the braces fixer

@Jean85 Interesting, but if you scroll down https://www.php-fig.org/psr/psr-12/#8-anonymous-classes , it seems there are not parenthesis - but there is no explanation and the example seems wrong to me, as () are normally needed when used some arguments needs to be passed to the constructor.

Related also with issue #4756 where the docs shows/allows empty block ({}) without new line before the closing brace.

btw., is this going from new_with_braces so if you don't like it you can already disable it?

If you read this strictly, it should apply to anonymous classes too.

however, the sample code in https://www.php-fig.org/psr/psr-12/#8-anonymous-classes does not contain the parenteses

I guess it's time for PSR-1212 😝

We (as @php-fig) can release an errata to clarify better this point. We'll discuss that in our ML: https://groups.google.com/d/topic/php-fig/F0IVXx1LL_Q/discussion

We're proposing a clarification with https://github.com/php-fig/fig-standards/pull/1206. The editor said that parentheses needed is the way to go.

@GrahamCampbell from a proposed PSR-12 ruleset above you are missing

        'method_argument_space' => [
            'on_multiline' => 'ensure_fully_multiline',
        ],

because of

Argument lists MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one argument per line.

can you create a ruleset called PSR12-beta or something like that in order to do testing?
I want to use it in our codebase.
thanks in advance.

You can still use the ruleset in your codebase, without it being an actual ruleset. Your suggestion is a bad idea because we cannot then later delete the ruleset due to semver. We'd have to call it psr12, from the beginning, and have it somewhat close to psr-12.

ok, @GrahamCampbell
Can you suggest how to use your provisional ruleset from commandline?

php-cs-fixer -fix . ruleset="???"

Sorry if you think that this temporary ruleset is useful because for me is not simple to use.
Do I have to patch master?

Thanks in advance.

You don't need to provide a ruleset. The expected way to use php-cs-fixer is to use a config file.

@GrahamCampbell thanks I will read the docs.
😄

A good example is the config file that this repo uses to fix itself (though you won't need the hacks they have at the bottom which are used to handle the case were an older version of the tool is used to execute the config file). ;)

Looks like the rule class_definition is messing with PSR-12, the space after class on anonymous classes is removed, and there is no option to avoid this behavior.

before:

-        $instance = new class () {
+        $instance = new class() {

According to PSR-12:

  • Anonymous Classes MUST follow the same guidelines and principles as closures...
  • Closures MUST be declared with a space after the function keyword...
  • When instantiating a new class, parentheses MUST always be present even when there are no arguments passed to the constructor. (previously discussed on this thread)

Thank you @eclipxe13, I updated the TODO list.

PSR12 states regarding importing traits:

it MUST have a blank line after the use import statement.

<?php

namespace Vendor\Package;

use Vendor\Package\FirstTrait;

class ClassName
{
    use FirstTrait;

    private $property;
}

I don't think that's possible right now with current rules, class_attributes_separation is the closest one but adds a space between every line, a space delimiting different types would be more appropriate:

...
class ClassName
{
    use FirstTrait;
    use SecondTrait;

    public const C1;
    public const C2;

    private $property1;
    private $property2;
    private $property3;

    public function xxxx()
    {
        .....
    }
}

We're missing a bullet point to make the unary spacing fixer configurable, to so PSR12 preset can use it without changing whitespace for the ! operator.

Hi there, outsider here wondering about the current status of this ticket?

I see there's a PR open to add the PSR12 ruleset which was posted 2 weeks ago. Are there plans to merge it soon? I'd love to get this working with my team's projects as soon as it is

I don't think it's ready yet. There are still lots of missing features from the fixers that need implementing.

Many of those are listed in the OP. The repo is open to PRs if anyone wants to have a go at implementing any part of them, even if it's just writing tests for stuff.

Should the @PSR2 ruleset be deprecated once the @PSR12 ruleset is stable?

Should the @PSR2 ruleset be deprecated once the @PSR12 ruleset is stable?

I don't think so - there's always going to be some poor sod out there stuck on an old codebase that might still find the ruleset useful.

When is it likely that @PSR12 will become available as a rule set?

Probably months. There's too much missing functionality. This repo is open to PRs. In particular, support PSR-12 style grouping of imports is a blocker for having this preset.

Thanks to all who's put effort into this. Your time is appreciated.

@JosephLeedy and @alexmatsak. Your downvotes show either a fundamental lack of understanding of how open source works, or that you feel other people should work for you for free. If you'd like things to move more quickly, either submit PRs implementing the missing fixers, or get a quote from someone to implement the features. Downvoting a comment which reflects reality is not helping anything, and certainly doesn't motivate people to work for free to deliver this!

Was this page helpful?
0 / 5 - 0 ratings