We do not yet have a consensus about how to write anonymous functions. Currently two different versions are in use in D8:

With a space between the function and the opening parenthesis:

  $callback = function ($parameter) use ($variable) {
  }

Or without a space between the function and the opening parenthesis:

  $callback = function($parameter) use ($variable) {
  }

Both are being used in the D8 codebase at the moment.

Suggested addition to / below https://www.drupal.org/coding-standards#functdecl:

Anonymous functions should have a space between "function" and its parameters, see the following example:

array_map(function ($item) {
  return $item['muh'];
}, $items);

Comments

nod_’s picture

for what it's worth, in JS we use the spaced version. function (whatever) {}.

pfrenssen’s picture

For me personally I like the look of the spaced version. It also resonates well with the current pattern of using a space before a language construct.

In the PHP manual itself both are used, example #1 showing the spaced version, example #2 the non-spaced one.

jhodgdon’s picture

Title: Define coding standards for anonymous functions (closures) » [policy] Define coding standards for anonymous functions (closures)
Issue tags: +Coding standards

pfrenssen: Can you provide examples of both in core, and are they both in use in *our* core code, vs. vendor code? Any idea about which is more prevalent?

pfrenssen’s picture

Example with space (from toolbar_pre_render()):

    $media_queries['toolbar']['breakpoints'] = array_map(                        
      function ($object) {                                                       
        return $object->mediaQuery;                                              
      },                                                                         
      $breakpoints->breakpoints                                                  
    );

Example without space (from config_get_entity_type_by_name()):

function config_get_entity_type_by_name($name) {                                 
  $entities = array_filter(entity_get_info(), function($entity_info) use ($name) {
    return (isset($entity_info['config_prefix']) && strpos($name, $entity_info['config_prefix'] . '.') === 0);
  });                                                                            
  return key($entities);                                                         
}

I tried grepping the codebase to get a count of both but this is not easy. This construct is also used in javascript and the word "function" is used a lot in documentation, skewing the results. The version with a space seems to be a tiny bit more popular.

Grepping inside the core folder, leaving out javascript and vendor files and prefixing the word "function" with a space (to skip false positives like drupal_register_shutdown_function) gives the following results:

$ grep -r " function(" | grep -v ".js" | grep -v vendor | wc -l
28
$ grep -r " function (" | grep -v ".js" | grep -v vendor | wc -l
32
jhodgdon’s picture

Thanks for the examples!

I agree with several commenters above that the space is more in line with our other coding standards. In the second example, it's especially glaring to me that it has function(something) use (something) -- spaces around use but not around function... kind of weird!

On the other hand, when we declare a function like
function foo($bar)
we don't leave a space between the function name and the arguments, so an anonymous function($bar) is kind of like that example too... Could go either way!

pfrenssen’s picture

Here are some new statistics of usage in current HEAD. Using a space is leaping ahead by 10 points over the non-spaced competitor.

$ grep -r " function(" | grep -v ".js" | grep -v vendor | wc -l
44
$ grep -r " function (" | grep -v ".js" | grep -v vendor | wc -l
54
jhodgdon’s picture

Project: Drupal core » Drupal Technical Working Group
Version: 8.0.x-dev »
Component: documentation » Documentation
Issue summary: View changes

Coding standards decisions are now supposed to be made by the TWG

pwolanin’s picture

I think it's also not clear (or not yet specified in the coding standards) the style we want to use for a lamda used inline for the callable for a function like array_filter()

This seems to be the style in core - "function" keyword and all the rest up to the opening { on the line with array_filter(), and then all the closing stuff on the final line:

    $tm = array_filter(get_class_methods($class), function ($method) {
      return strpos($method, 'test') === 0;
    });

This seems to be what PSR-2 expects, so I don't really think there is a debate.

I only mention this as needing clarity since I was reviewing a patch that had it formatted quite differently, and I had to guess at a standard based on current usage.

it was more like:

    $tm = array_filter(get_class_methods($class), 
      function ($method) {
        return strpos($method, 'test') === 0;
      }
    );
grom358’s picture

At the moment (barely any php files may have missed) there are 154 anonymous functions where there space after the function keyword "function (" and 102 anonymous functions where no space "function(".

Always a space after the use keyword (100 of the anonymous functions have lexical variables).

pwolanin’s picture

https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-codi...

their example is:


$app->get('/hello/{name}', function ($name) use ($app) { 
    return 'Hello '.$app->escape($name); 
});

Which has spaces both paces.

pfrenssen’s picture

If it's accepted in PSR-2 then that is a big + to the spaced version.

tizzo’s picture

Project: Drupal Technical Working Group » Coding Standards
frob’s picture

I would vote for this to follow the JavaScript coding standards as outlined by nod_ in #1.

pfrenssen’s picture

The current tally is:

  • In favour of the spaced version: @nod_, @pwolanin, @frob and me
  • In favour of the non-spaced version: nobody
  • The majority of instances in core use the spaced version, so this can be considered the de facto standard.

I guess the consensus it pretty clear. Shall we do a write up?

frob’s picture

Sounds good to me.

dawehner’s picture

Issue summary: View changes
Status: Active » Needs review
markdorison’s picture

Issue tags: +needs announcement for final discussion
tizzo’s picture

Issue tags: -needs announcement for final discussion +final discussion
chx’s picture

Edit: deleted.

joelpittet’s picture

Spaced, +1

Crell’s picture

PSR-2 specifies a space after the function keyword: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-codi...

Since it looks like we're going that direction anyway on closures, I'd recommend either copying the text from PSR-2 or simply linking to that section of PSR-2. No sense being different when there's no reason to.

pfrenssen’s picture

Awesome that this is actually in the PSR-2 standard. Great idea to base this on the text from PSR-2, but it seems their writing style differs a lot from ours. Ours sounds a lot friendlier and more helpful :)

tizzo’s picture

Project: Coding Standards » Drupal core
Version: » 8.3.x-dev
Component: Documentation » other
Status: Needs review » Reviewed & tested by the community
Issue tags: -Coding standards, -final discussion +approved, +needs documentation updates

The coding standards committee feels this has enough support - sending to core for approval.

xjm’s picture

Status: Reviewed & tested by the community » Needs review

Is there an available phpcs rule for this standard?

frob’s picture

@xjm, I just added

  $param = '';

  $callback = function($nothing) use ($param) {
    echo $nothing;
  };

to an existing module and got:

536 | ERROR | [x] Expected 1 space after FUNCTION keyword; 0 found

As the response.

Changing this to:

  $param = '';

  $callback = function ($nothing) use ($param) {
    echo $nothing;
  };

Passed without error.

xjm’s picture

Project: Drupal core » Coding Standards
Version: 8.3.x-dev »
Component: other » Coding Standards
Status: Needs review » Reviewed & tested by the community
Issue tags: +Core Committer Approved

Excellent, this standard is approved then. Thanks @frob.

I filed #2794567: Make core comply with new standard spacing for anonymous functions and enable the rule in phpcs.xml.dist to make core compliant.

xjm’s picture

Issue tags: +8.2.0 release notes
Mile23’s picture

Here's an example from ConfigManager: http://cgit.drupalcode.org/drupal/tree/core/lib/Drupal/Core/Config/Confi...

    foreach (['config', 'content'] as $dependency_type) {
      $affected_dependencies[$dependency_type] = array_combine(
        array_map(function ($entity) { return $entity->getConfigDependencyName(); }, $affected_dependencies[$dependency_type]),
        $affected_dependencies[$dependency_type]
      );
    }

Drupal.WhiteSpace.ScopeClosingBrace thinks it should look like this, when phpcbf auto-fixes it:

    foreach (['config', 'content'] as $dependency_type) {
      $affected_dependencies[$dependency_type] = array_combine(
        array_map(function ($entity) { return $entity->getConfigDependencyName();
        }, $affected_dependencies[$dependency_type]),
        $affected_dependencies[$dependency_type]
      );
    }

To me, it should look like this:

    foreach (['config', 'content'] as $dependency_type) {
      $affected_dependencies[$dependency_type] = array_combine(
        array_map(
          function ($entity) {
            return $entity->getConfigDependencyName();
          },
          $affected_dependencies[$dependency_type]
        ),
        $affected_dependencies[$dependency_type]
      );
    }

I bring this up because we have an issue postponed on this very question, and the example is from the patch: #2572795: Fix coding standard for closures - Drupal.WhiteSpace.ScopeClosingBrace and Generic.Functions.OpeningFunctionBraceKernighanRitchie

When this question is answered, we'll need to be sure and file an issue against Coder to support it.

Mile23’s picture

pfrenssen’s picture

Yes the auto-fixed example from #28 is wrong, the code between curly braces should be on a new line. It's not strictly needed to put all function arguments on new lines, so it will probably be easier in Coder to fix it to this:

    foreach (['config', 'content'] as $dependency_type) {
      $affected_dependencies[$dependency_type] = array_combine(
        array_map(function ($entity) {
          return $entity->getConfigDependencyName();
        }, $affected_dependencies[$dependency_type]),
        $affected_dependencies[$dependency_type]
      );
    }

I'll create the issue in Coder.

pfrenssen’s picture

Off topic, I personally think that piece of code should be rewritten for legibility :) Having an anonymous function inline inside 2 nested function calls becomes a bit hard to follow. But it is allowed by the coding standards :)

I'd prefer something like this:

    $get_entity_name = function ($entity) {
      return $entity->getConfigDependencyName();
    };
    foreach (['config', 'content'] as $dependency_type) {
      $map = array_map($get_entity_name, $affected_dependencies[$dependency_type]);
      $affected_dependencies[$dependency_type] = array_combine($map, $affected_dependencies[$dependency_type]);
    }
pfrenssen’s picture

This meets all requirements for inclusion in the coding standards now. We have a proposed description which is core committer approved. There is an issue to fix it in core: #2572795: Fix coding standard for closures - Drupal.WhiteSpace.ScopeClosingBrace and Generic.Functions.OpeningFunctionBraceKernighanRitchie. There is an outstanding bug regarding autofixing inline closures (#2795669: Incorrect autofix of anonymous function body in Drupal.WhiteSpace.ScopeClosingBrace) but that doesn't block this.

Next steps is to update the documentation and unpostpone #2572795: Fix coding standard for closures - Drupal.WhiteSpace.ScopeClosingBrace and Generic.Functions.OpeningFunctionBraceKernighanRitchie.

Mile23’s picture

We can't unpostpone #2572795: Fix coding standard for closures - Drupal.WhiteSpace.ScopeClosingBrace and Generic.Functions.OpeningFunctionBraceKernighanRitchie until Coder is fixed. The desire is for the autofix to get it right, because that issue doesn't only fix closures.

pfrenssen’s picture

Just as a heads up, #2572795: Fix coding standard for closures - Drupal.WhiteSpace.ScopeClosingBrace and Generic.Functions.OpeningFunctionBraceKernighanRitchie is now unpostponed. This was not blocking this issue, but it's definitely good news that this is ready to be implemented in core too.

pfrenssen’s picture

Status: Reviewed & tested by the community » Postponed

This was discussed during the coding standards committee meeting. This coding standard change has been approved. We will wait until core is compliant before updating the documentation. Postponing this on #2572795: Fix coding standard for closures - Drupal.WhiteSpace.ScopeClosingBrace and Generic.Functions.OpeningFunctionBraceKernighanRitchie.

frob’s picture

@pfrenssen, postponing this doesn't make sense to me. While it is a good goal, to only have coding standards that core has fully conformed to, by not modifying the coding standard doc until after that is done we run the risk of modules/contributors using the wrong code style in the meantime.

pfrenssen’s picture

@frob I think you have a good point. We try to get core compliant before publishing the new standard so that it can set the example. Usually this doesn't take much time. For this issue we aimed to get it done before the release of 8.2.0, which is scheduled for tomorrow.

Fixing this in core is actually not very straightforward. To get this in we need to fix a long chain of blockers, and it looks like this will take quite some time.

Here is the current list of blockers to get this done in core:

  1. #2572795: Fix coding standard for closures - Drupal.WhiteSpace.ScopeClosingBrace and Generic.Functions.OpeningFunctionBraceKernighanRitchie
  2. #2803779: Update Coder to 8.2.10 and fix errors from improved sniffs
  3. #2744463: Add phpcs, coder 8.2.8 as --dev requirements for drupal/core
  4. #2745355: Use "composer install --no-dev" to create tagged core packages
  5. #2804663: Have simpletest, run-tests.sh enforce their dependency on PHPUnit in 8.1.x

It will take weeks, or maybe even months to get through this chain of issues.

Can any of the core committers weigh in, can we publish this new coding standard and let core become compliant when it is ready for it?

xjm’s picture

Issue tags: -8.2.0 release notes

AFAIK there aren't that many violations in core, so I'm not too worried one way or the other. It's less confusing for developers than something where core actually does not follow a standard at all, or only half follows it, etc.

That said though, I also don't think modules using the wrong style in the meantime is a risk really. We're not ready to adopt the standard yet. That's okay. We can adopt it with 8.3.0 in six months. We could put a note in the docs that core is not yet compliant, I guess, but it doesn't seem that urgent to me one way or another.

The coder issues don't need to be postponed, for sure.

frob’s picture

I only bring it up because I happen to find this issue while looking for the drupal coding standards for anonymous functions.

I would expect that I am not an edge case, as in I would expect that there are other people who have looked for coding standards for anonymous functions and might get confused by our lack of standards on them.

pfrenssen’s picture

Status: Postponed » Fixed

The coding standards have been updated so they now cover closures: https://www.drupal.org/docs/develop/standards/coding-standards#functdecl

I haven't put a note in the documentation to mention that core is not compliant yet. I think it's still a bit too early for that. We still have a large number of outstanding coding standards issues for core, so there is no general expectation yet that core is fully compliant (ref #2571965: [meta] Fix PHP coding standards in core). Once core is 99% compliant it would be more appropriate to make a mention of this.

xjm’s picture

I don't think this is actually fixed until coder and core are done and we officially adopt the standard, as I said in #39. It would be useful to track the issue on the TWG until that's done. Thoughts?

frob’s picture

It looks like we don't have an issue to track the docs change other than this one. It would make more sense if we did as this is just labeled as a policy issue. Not sure if there is an established workflow for that.

pfrenssen’s picture

The documentation and Coder are both updated, the core issue is tracked in #2572795: Fix coding standard for closures - Drupal.WhiteSpace.ScopeClosingBrace and Generic.Functions.OpeningFunctionBraceKernighanRitchie. We can leave this open for visibility until that is fixed.

BTW core is by and far compliant with this already, the actual violations are very few.

I'm not entirely sure about if it's a good idea to have a coupling between the coding standards documentation and core compliance in tandem with minor updates. Not being able to make any changes to the standards until 8.3.0 comes around seems counterproductive.

pfrenssen’s picture

Status: Fixed » Reviewed & tested by the community
Issue tags: -approved, -needs documentation updates

Reopening for visibility until core is compliant.

Mile23’s picture

Status: Reviewed & tested by the community » Fixed
xjm’s picture

Status: Fixed » Reviewed & tested by the community

Thanks @Mile23! Let's keep this at not-fixed though until that lands or is scheduled.

(Maybe we could have different components for issues that are ratified but not yet adopted or something.)

xjm’s picture

Issue tags: +8.3.0 release notes
quietone’s picture

The implementation for this was done in #2572795: Fix coding standard for closures - Drupal.WhiteSpace.ScopeClosingBrace and Generic.Functions.OpeningFunctionBraceKernighanRitchie and this change is in the release notes for 8.3.0-alpha1.

There is nothing more to do here.

Thanks!

quietone’s picture

Status: Reviewed & tested by the community » Fixed

this time really mark it fixed.

Status: Fixed » Closed (fixed)

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