Allow multi-line function declarations

Created on 11 July 2022, almost 3 years ago
Updated 24 May 2024, 11 months ago

Problem/Motivation

Splitting #1539712: [policy, no patch] Coding standards for breaking function calls and language constructs across lines โ†’ as suggested #1539712-92: [policy, no patch] Coding standards for breaking function calls and language constructs across lines โ†’ and agreed at a #3282227: Coding Standards Meeting 2022-06-07 2100 UTC โ†’

Option A (from PSR-12)

When declaring functions, 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.

When the argument list is split across multiple lines, the closing parenthesis and opening brace MUST be placed together on their own line with one space between them. When you have a return type declaration present, there MUST be one space after the colon followed by the type declaration. The colon and declaration MUST be on the same line as the argument list closing parenthesis with no spaces between the two characters.

When the argument list is split across multiple lines, the last argument in the list SHOULD use a trailing comma. Trailing commas are supported since PHP 8.0.

Option A is viewed as an improvement over status quo (Option B) for several reasons:

  • improved code readability.
  • cleaner, simpler diffs, patches, and git blame history.
  • consistency with other non Drupal PHP projects.
  • ease of adding attributes for auto-injection later.

Here is a code sample from PSR-12 (linked above) that has been adapted for Drupal's coding conventions (including the 2-space indentation and placing opening bracket on the same line as class declaration) and adds the trailing comma best practice to the last argument:


// A simple function example.
function a_very_long_function_name(
  ClassTypeHint $arg1,
  &$arg2,
  array $arg3 = [],
) {
  // function body
}

// A simple class method example.
class ClassName {
  public function aVeryLongMethodName(
    ClassTypeHint $arg1,
    &$arg2,
    array $arg3 = [],
  ) {
    // method body
  }
}

// A simple function example with return types.
function a_very_long_function_name_with_return_type(
  string $foo,
  string $bar,
  int $baz,
): string {
  return 'foo';
}

// A class method example with return types.
class ReturnTypeVariations {
  public function aFunctionWithReturnType(
    string $foo,
    string $bar,
    int $baz,
  ): string {
    return 'foo';
  }
}

Option B from #1539712-4: [policy, no patch] Coding standards for breaking function calls and language constructs across lines โ†’

Function declarations MUST be written on a single line; they should never wrap multiple lines.

Benefits

If we adopted this change, the Drupal Project would benefit by ...

Three supporters required

  1. jwilson3
  2. alex.skrypnyk โ†’
  3. steinmb

Proposed changes

Provide all proposed changes to the Drupal Coding standards โ†’ . Give a link to each section that will be changed, and show the current text and proposed text as in the following layout:

1. Function Declarations โ†’

function funstuff_system($field) {
  $system["description"] = t("This module inserts funny text into posts randomly.");
  return $system[$field];
}

Arguments with default values go at the end of the argument list. Always attempt to return a meaningful value from a function if one is appropriate.

function funstuff_system(
  string $foo,
  string $bar,
  int $baz,
) {
  // body
}

Argument lists may be split across multiple lines, where each subsequent line is indented once.

When the argument list is split across multiple lines

  • The first item in the list must be on the next line.
  • There must be only one argument per line.
  • The last argument in the list must use a trailing comma.
  • The closing parenthesis and opening brace must be placed together on their own line with one space between them.

Remaining tasks

Option A has overwhelming support from community members in comments #5 #6 #8 #9 #10 #11 #12 #13 #14 #16.

  1. ๐Ÿ“Œ Add rule for multi-line function declarations Fixed

For a fuller explanation of these steps see the Coding Standards project page โ†’

๐Ÿ“Œ Task
Status

Fixed

Component

Drupal Core Standards

Created by

๐Ÿ‡ณ๐Ÿ‡ฟNew Zealand quietone

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • ๐Ÿ‡ช๐Ÿ‡ธSpain penyaskito Seville ๐Ÿ’ƒ, Spain ๐Ÿ‡ช๐Ÿ‡ธ, UTC+2 ๐Ÿ‡ช๐Ÿ‡บ

    +1 to A+trailing comma

    I'm not a fan of how it looks like, but I'll get used to it (as if you care :-P) and adopting PSR is always worth it.

  • Status changed to Needs work about 2 years ago
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States dww

    It looks like this has overwhelming support for option A. We need to update the summary with examples, including proposed changes to docs.

    Otherwise, I think this is ready for public announcement and to finalize the steps to get it adopted.

  • ๐Ÿ‡ช๐Ÿ‡จEcuador jwilson3

    How about this for an update. I took the code examples from #5 and added trailing comma to last arg.

  • ๐Ÿ‡ช๐Ÿ‡จEcuador jwilson3

    Added #14 to issue summary.

  • ๐Ÿ‡ช๐Ÿ‡จEcuador jwilson3

    whitespace fix in code sample.

  • ๐Ÿ‡ณ๐Ÿ‡ฑNetherlands arkener

    +1 to option A with required trailing commas.

  • Status changed to Needs review about 2 years ago
  • ๐Ÿ‡ช๐Ÿ‡จEcuador jwilson3

    I removed the "Needs issue summary update" but forgot to set the status back to NR.

  • Status changed to RTBC about 2 years ago
  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom longwave UK

    The issue summary looks good to me, and the issue has been open for 9 months with no disagreement so I think this is ready to move to RTBC.

  • ๐Ÿ‡บ๐Ÿ‡ธUnited States dww

    Indeed, and https://github.com/php-fig/per-coding-style/blob/2.0.0/spec.md#45-method... includes:

    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.

    When the argument list is split across multiple lines, the closing parenthesis and opening brace MUST be placed together on their own line with one space between them. For example:

    
    namespace Vendor\Package;
    
    class ClassName
    {
        public function aVeryLongMethodName(
            ClassTypeHint $arg1,
            &$arg2,
            array $arg3 = [],
        ) {
            // method body
        }
    }
    

    ...
    When you have a return type declaration present, there MUST be one space after the colon followed by the type declaration. The colon and declaration MUST be on the same line as the argument list closing parenthesis with no spaces between the two characters. For example:

        public function anotherFunction(
            string $foo,
            string $bar,
            int $baz,
        ): string {
            return 'foo';
        }
    

    ๐ŸŽ‰ We do a few things differently (e.g. 2 spaces for indent, the { on class declarations, etc), but otherwise, this is exactly what we're proposing. Ship it! ๐Ÿ˜‰

  • ๐Ÿ‡ช๐Ÿ‡จEcuador jwilson3

    When you have a return type declaration present, there MUST be one space after the colon followed by the type declaration. The colon and declaration MUST be on the same line as the argument list closing parenthesis with no spaces between the two characters.

    I added this blurb to the IS. I noticed it before but thanks for catching this to be more explicit.

  • ๐Ÿ‡ช๐Ÿ‡จEcuador jwilson3

    mention Drupal's coding conventions that explicitly differ from PSR-12 in IS

  • ๐Ÿ‡ช๐Ÿ‡จEcuador jwilson3

    ๐Ÿคฆโ€โ™‚๏ธ

  • ๐Ÿ‡ฆ๐Ÿ‡บAustralia alex.skrypnyk Melbourne

    +1 on Option A

  • ๐Ÿ‡ฆ๐Ÿ‡บAustralia larowlan ๐Ÿ‡ฆ๐Ÿ‡บ๐Ÿ.au GMT+10

    Draft CR

  • ๐Ÿ‡ณ๐Ÿ‡ฟNew Zealand quietone

    Adding new template as best I can.

  • ๐Ÿ‡ณ๐Ÿ‡ฟNew Zealand quietone

    As I reviewed this I realized that there are outstanding issues for two of the changes here. There are โœจ Revise coding standards to use IETF RFC 2119 standards Closed: won't fix and #2928856: Adopt the PSR-12 standard for PHP7 return types โ†’ . Because of the I have removed those changes and am tagging for a change record update.

    I also removed repeated text and used a list format. That is what I see in the existing standards.

  • Status changed to Needs review over 1 year ago
  • ๐Ÿ‡ณ๐Ÿ‡ฟNew Zealand quietone

    Setting to Needs Review so the doc changes can be reviewed and then the CR updated.

  • Status changed to RTBC over 1 year ago
  • ๐Ÿ‡ฆ๐Ÿ‡บAustralia larowlan ๐Ÿ‡ฆ๐Ÿ‡บ๐Ÿ.au GMT+10

    Looks good, I'll update the CR

  • ๐Ÿ‡ฆ๐Ÿ‡ฒArmenia murz Yerevan, Armenia

    I created a similar improvement to allow multi-line conditions: #3392321: Relax the "Conditions should not be wrapped into multiple lines" rule for more code readability โ†’ - please support it too ;)

  • ๐Ÿ‡ซ๐Ÿ‡ทFrance andypost

    RTBC++

  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom catch

    +1 from me, and the CR looks good (and easier to read than the version in the issue summary).

  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom AaronMcHale Edinburgh, Scotland

    +1, agree with everything here, supporting Option A.

  • ๐Ÿ‡ฆ๐Ÿ‡บAustralia larowlan ๐Ÿ‡ฆ๐Ÿ‡บ๐Ÿ.au GMT+10

    This was discussed at the coding standards committee meeting and @dww, @bbrala, @AaronMcHale and myself were +1.

    I think this needs to go out in an announcement now.

  • ๐Ÿ‡ณ๐Ÿ‡ฟNew Zealand quietone

    This is tagged for change record updates which I think should be done before the announcement. Have they been done?

  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom catch

    Looks to me like they were done? https://www.drupal.org/node/3396762/revisions/view/13284559/13286250 โ†’ but I'm not 100% confident those were the same changes you tagged for, so leaving the tag on...

  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom jonathan1055

    I made a minor change to proposed text, to swap the last two bullet points around. Logically it makes sense to talk about the final item in the list before talking about the closing parenthesis and opening brace.

    I also notice that the following text has been dropped from the existing standard

    Arguments with default values go at the end of the argument list. Always attempt to return a meaningful value from a function if one is appropriate

    Was this by accident? Is the order of arguments still important? I think it is, and that first sentence should be added back.

    I know this is RTBC and these changes should not impact the upcoming blog post. Its just the details of the wording, we all agree that the new standard will go ahead.

  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom catch

    Arguments with default values go at the end of the argument list. Always attempt to return a meaningful value from a function if one is appropriate

    I think this is already enforced somewhere - maybe phpstan? I'm not sure it is really coding style as such, feels like an actual bug if optional arguments aren't at the end.

  • ๐Ÿ‡ฆ๐Ÿ‡บAustralia darvanen Sydney, Australia

    feels like an actual bug if optional arguments aren't at the end.

    Pretty sure it's a 500 error in PHP 8.1

  • ๐Ÿ‡ฎ๐Ÿ‡นItaly mondrake ๐Ÿ‡ฎ๐Ÿ‡น

    Itโ€™s deprecated since 8.1.0, https://3v4l.org/JPtv7

  • ๐Ÿ‡ฆ๐Ÿ‡บAustralia larowlan ๐Ÿ‡ฆ๐Ÿ‡บ๐Ÿ.au GMT+10

    This was discussed at core committers meeting on Wed December 5th (UTC)
    There were no objections

    Completing steps 6 and 7.

    Next step is the documentation edits and core issue for phpcs rule (which may be a case of relaxing a rule in this instance).

  • ๐Ÿ‡ฆ๐Ÿ‡บAustralia nigelcunningham Geelong

    I know it's too late now but trailing commas are ugly, unnecessary extra work for the parser and only useful when you're adding another arg later on. They should be removed from the array requirement, not added elsewhere!

  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom jonathan1055

    Hi Nigel Cunningham,
    Yes you are right that it is a bit late, we have completed step 7 out of 9 and we have 29 followers on the issue and no disagreement on the standard as proposed. Thank you for making the suggestion, everyone's input is appreciated and hopefully you will take part in other Coding Standards issues, there are plenty more that need discussion and agreements. But this one is pretty much done and dusted :-)
    Jonathan

  • ๐Ÿ‡ณ๐Ÿ‡ฟNew Zealand quietone

    There are already instance of this in core, for example, mstrelan pointed out in Slack, \Drupal\Core\Extension\DatabaseDriver::__construct

  • ๐Ÿ‡บ๐Ÿ‡ธUnited States dww

    That (and many like it) don't adhere to the standard we're laying out:

    When the argument list is split across multiple lines

    • The first item in the list must be on the next line.
    • There must be only one argument per line.
    • The last argument in the list must use a trailing comma.
    • The closing parenthesis and opening brace must be placed together on their own line with one space between them.

    Current:

      public function __construct(
        string $root,
        protected Extension $module,
        protected string $driverName,
        protected array $discoveredModules) {
        $this->root = $root;
        $this->type = 'database_driver';
      }
    

    Per above "must" statements, this should become:

      public function __construct(
        string $root,
        protected Extension $module,
        protected string $driverName,
        protected array $discoveredModules,
      ) {
        $this->root = $root;
        $this->type = 'database_driver';
      }
    

    Don't we want a sniff about that? If this is our standard, we should adopt it core-wide and have our tooling enforce it. I presume a sniff that would flag this could be configured to ignore single line function declarations, right?

  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom jonathan1055

    Thanks @dww, that's useful info. But writing sniffs, or finding existing ones to include, will be covered in step 9 of the process. That does not hinder the progress of getting the standard updated. Is that right?

    Currently we are at step 8 "Needs documentation updates". I can see there was a Slack thread on this at the meeting. If everything is agreed, can we proceed to update the docs?

  • ๐Ÿ‡ณ๐Ÿ‡ฟNew Zealand quietone

    I have made the edit to the doc page and published the CR

  • ๐Ÿ‡ณ๐Ÿ‡ฟNew Zealand quietone

    Forgot to remove the tag.

    Who can followup with issues for Code etc.

  • ๐Ÿ‡บ๐Ÿ‡ธUnited States cmlara

    Should this be marked as Fixed per the step 8 procedures or left open because step 9 work is needed?

    8. Drupal.org coding standards pages are updated for approved proposals. Issues are marked "fixed" and the โ€œNeeds documentation updatesโ€ tag removed, change record published etc.
    9. When a PHP standard is approved use the following to determine the next steps.

  • ๐Ÿ‡บ๐Ÿ‡ธUnited States dww

    Yeah, we need to open the follow-up now to:

    1. Find / enable sniffs to enforce this.
    2. Update core to be compliant.

    Only once that exists and is linked here can we fully close this one out.

    Thanks,
    -Derek

  • ๐Ÿ‡ณ๐Ÿ‡ฟNew Zealand quietone

    The sniff is Squiz.Functions.MultiLineFunctionDeclaration but I can find no documentation for it.

    Core is using that sniff

      <rule ref="Squiz.Functions.MultiLineFunctionDeclaration.BraceOnSameLine">
        <severity>0</severity>
      </rule>
      <rule ref="Squiz.Functions.MultiLineFunctionDeclaration.CloseBracketLine">
        <severity>0</severity>
      </rule>
      <rule ref="Squiz.Functions.MultiLineFunctionDeclaration.ContentAfterBrace">
        <severity>0</severity>
      </rule>
      <!-- Standard yet to be finalized on this (https://www.drupal.org/node/1539712). -->
      <rule ref="Squiz.Functions.MultiLineFunctionDeclaration.FirstParamSpacing">
        <severity>0</severity>
      </rule>
      <rule ref="Squiz.Functions.MultiLineFunctionDeclaration.Indent">
        <severity>0</severity>
      </rule>
    

    I tested by changing \Drupal\Core\DrupalKernel::handleException to

      protected function handleException(
        \Exception $e,
        $request,
        $type,
      ) {

    I then ran the commit-code-checks and there were no errors. So, Coder is not preventing using this new standard.

    I changed to incorrect indentation as shown.

      protected function handleException(
        \Exception $e,
           $request,
        $type,
      ) {

    And tested again and this passes phpcs.

    I then remove this rule

      <rule ref="Squiz.Functions.MultiLineFunctionDeclaration.Indent">
        <severity>0</severity>
      </rule>

    And tested again. This time the indentation error was found. However, phpcs reports heaps of other errors in core. The ones I checked had correct indentation. Plus it was reporting errors from sniffSquiz.Functions.MultiLineFunctionDeclaration.BraceOnSameLine which was not changed. That seems wrong.

  • ๐Ÿ‡ณ๐Ÿ‡ฟNew Zealand quietone
  • ๐Ÿ‡ฆ๐Ÿ‡นAustria klausi ๐Ÿ‡ฆ๐Ÿ‡น Vienna

    This was implemented in Coder, only the trailing comma rule is missing for now. Opened โœจ Validate trailing comma in multi-line function declaration Active for that.

  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom jonathan1055

    Klausi has released coder 8.3.24
    https://www.drupal.org/project/coder/releases/8.3.24 โ†’

    For contrib gitlab pipelines, the Coder 8.3.24 will be used immediately. So be prepared for some failing contrib phpcs jobs and the need for support. What would be the mechanism by which we give maintainers notice that this is going to happen? This issue is still RTBC, but looks like all the 9 steps are done.

  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom longwave UK

    The change in Coder seems to work well, we upgraded to this on a work project yesterday and phpcbf correctly fixed both spacing and trailing commas on all our badly formatted multiline constructors - we use property promotion a lot but our formatting was not consistent before.

  • ๐Ÿ‡ฆ๐Ÿ‡นAustria klausi ๐Ÿ‡ฆ๐Ÿ‡น Vienna

    Happy to hear it is working - we have also deployed it over our work codebases and are quite happy with the auto fixes.

  • ๐Ÿ‡ณ๐Ÿ‡ฑNetherlands bbrala Netherlands

    Made an issue for core, needs quite a few fixes :)

    ๐Ÿ“Œ Fix Drupal.Functions.MultiLineFunctionDeclaration coding standard Needs review

  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom jonathan1055

    Just reporting here for info, and to help others, that the change to add a trailing comma is not compatible with PHPUnit 9.6.19 in Drupal 9.5 PHP 7.4 (which is what you get when using OPT_IN_TEST_PREVIOUS_MAJOR on gitlab pipelines). The phpunit test complains of a syntax error and gives

    ParseError: syntax error, unexpected ')', expecting variable (T_VARIABLE)
    

    So if you want to fix the PHPCS rule and still maintain the ability to test at 'Previous Major' you can ignore the rule on the next line:

        ModuleHandlerInterface $module_handler,
        // Trailing comma is incompatible with PHPUnit 9.6.19 in Drupal 9.5 PHP 7.4.
        // phpcs:ignore Drupal.Functions.MultiLineFunctionDeclaration.MissingTrailingComma
        EntityTypeManagerInterface $entity_type_manager
      ) {
    
  • Status changed to Fixed 12 months ago
  • ๐Ÿ‡ณ๐Ÿ‡ฑNetherlands bbrala Netherlands

    THis is all done. Followup is posted, cr also.

  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.71.5 2024