Sharing configurations for PHP-CS-Fixer across projects
You are working on PHP applications and packages and use friendsofphp/php-cs-fixer
to enforce coding standards.
What are your options for sharing your configurations for friendsofphp/php-cs-fixer
to enforce a consistent coding standard across these projects in your organization?
Configuring PHP-CS-Fixer
You can configure friendsofphp/php-cs-fixer
with command line options only or by using a configuration file. I recommend using a configuration file.
The configuration file, typically with the name .php-cs-fixer.php
or .php-cs-fixer.dist.php
, contains PHP and needs to return a configuration object.
<?php
declare(strict_types=1);
use PhpCsFixer\Config;
$config = new Config();
// ...
return $config;
The configuration object must configure a finder that supplies friendsofphp/php-cs-fixer
with a list of files to inspect.
<?php
declare(strict_types=1);
use PhpCsFixer\Config;
use PhpCsFixer\Finder;
$finder = Finder::create()
->exclude([
'.build/',
'.github/',
])
->in(__DIR__);
$config = new Config();
$config->setFinder($finder)
return $config;
The configuration object can optionally configure zero or more of the 38 rulesets and 250 rules.
If you do not configure any rulesets or rules, friendsofphp/php-cs-fixer
currently uses @PSR12
as default ruleset.
If you configure one or more of the available rulesets and rules, friendsofphp/php-cs-fixer
will create, configure, and apply the corresponding fixers to the PHP files.
<?php
declare(strict_types=1);
use PhpCsFixer\Config;
use PhpCsFixer\Finder;
$finder = Finder::create()
->exclude([
'.build/',
'.github/',
])
->in(__DIR__);
$config = new Config();
$config
->setFinder($finder)
->setRules([
// one or more of 38 rulesets
'@PSR12' => true,
// one or more of 250 rules for fixers
'blank_line_before_statement' => [
'statements' => [
'break',
'case',
'continue',
// ...
],
// ...
'yoda_style' => true,
]);
return $config;
Since the location of PHP files will differ from one project to another, you will want to configure the finder per project and are only concerned with sharing the configuration of rulesets and rules across projects.
Sharing configurations for PHP-CS-Fixer using a GitHub template repository
If you use GitHub and do not feel like setting up a new project from scratch every time, you probably already have a GitHub template repository.
A GitHub repository template, such as ergebnis/php-package-template
enables you to set up a new project quickly - which could be an ideal location for maintaining a configuration of rulesets and rules for friendsofphp/php-cs-fixer
.
But, you may realize that the PHP applications and packages you build have very different requirements and setups, so maybe you need more than one GitHub repository template.
So which of these GitHub template repositories should now be the source of truth for your configurations of rulesets and rules for friendsofphp/php-cs-fixer
?
Also, you may realize that you need to support a wide range of PHP versions, requiring different configurations for friendsofphp/php-cs-fixer
. So how can you make sure that you use the correct configuration?
And, even if you had only a single GitHub repository template where you maintain a configuration of rulesets and rules for friendsofphp/php-cs-fixer
, how would you propagate the configuration of rulesets and rules to all of your other projects?
Copying the configurations from there and pasting them into a PHP project whenever you pick up work could be an option.
But this option is prone to errors. And how do you know whether the configuration in the central location has changed since you last worked on a specific project?
If we only had a delivery mechanism for distributing configurations!
Sharing configurations for PHP-CS-Fixer using a PHP package
As Paul Redmond rightly points out in his recent article about sharing configurations of rules for squizlabs/php_codesniffer
(an alternative to friendsofphp/php-cs-fixer
), the ideal solution for sharing and propagating configurations is a PHP package.
A PHP package can not only provide files, such as the XML configuration files for PHPCS in Paul's article, or PHP files or classes returning or creating arrays of rulesets and rules configurations for friendsofphp/php-cs-fixer
, but also declare dependencies.
As friendsofphp/php-cs-fixer
evolves, contributors and maintainers add, deprecate, and remove fixers and configuration options. You certainly want to ensure that your configuration of rulesets and rules works well with the version of friendsofphp/php-cs-fixer
you use in your projects. You can achieve that by declaring the dependency on friendsofphp/php-cs-fixer
in the PHP package instead of the consuming application or package.
A PHP package can receive automated updates via Dependabot, Renovate Bot, or similar services.
If you set up the PHP package cleverly, you can use these automated updates to discover added, deprecated, and removed fixers and configuration options with automated tests. Automatic discovery of new fixers and configuration options allows you to use the full potential of fixers that friendsofphp/php-cs-fixer
provides and can free up time for more pressing problems than manually fixing coding standard violations.
Last but not least, by using Dependabot, Renovate Bot or similar services, you can propagate the configurations of rulesets and rules from your PHP package, which can now become the single source of truth of configurations for friendsofphp/php-cs-fixer
, to all of your other PHP applications and packages.
The simplest solution would be to create one or more PHP files in your package that return the configuration of rulesets and rules.
<?php
declare(strict_types=1);
return [
// one or more of 38 rulesets
'@PSR12' => true,
// one or more of 250 rules for fixers
'blank_line_before_statement' => [
'statements' => [
'break',
'case',
'continue',
// ...
],
// ...
'yoda_style' => true,
];
Then you can require the PHP file downstream in your configuration for PHP-CS-Fixer.
<?php
declare(strict_types=1);
use PhpCsFixer\Config;
use PhpCsFixer\Finder;
$rules = require __DIR__ . '/vendor/ergebnis/php-cs-fixer-config/config/php82.php';
$finder = Finder::create()
->exclude([
'.build/',
'.github/',
])
->in(__DIR__);
$config = new Config();
$config
->setFinder($finder)
->setRules($rules);
return $config;
But why not extract a factory and concrete classes providing configurations of rulesets and rules that create the configurations for you?
For example, a factory could ensure that you are running friendsofphp/php-cs-fixer
on the appropriate version of PHP. A factory could also further prepare the configuration object. Concrete classes for PHP-version-specific rulesets could allow you to override rules for project-specific configurations. A factory and classes also have the advantage that they are autoloadable, and you do not have to deal with exact file locations.
<?php
declare(strict_types=1);
use Ergebnis\PhpCsFixer;
$config = PhpCsFixer\Config\Factory::fromRuleSet(new PhpCsFixer\Config\RuleSet\Php82('', [
'date_time_immutable' => false,
'mb_str_functions' => false,
]);
$config->getFinder()
->exclude([
'.build/',
'.github/',
'var/',
])
->in(__DIR__);
return $config;
Concrete examples from the field
In 2015, while supplying services for Refinery29, Inc., I started working on refinery29/php-cs-fixer-config
.
As far as I can tell, this was the first PHP package that shared configurations of rulesets and rules for friendsofphp/php-cs-fixer
, inspiring many others you can find on Packagist today.
Since 2015, I have successfully applied and refined this approach in ergebnis/php-cs-fixer-config
, which I use in all my projects.
For your convenience, I have extracted a GitHub template repository at ergebnis/php-cs-fixer-config-template
as a perfect starting point to create, share, and distribute configurations of rulesets and rules for friendsofphp/php-cs-fixer
.
Take a look - you will not regret it!
Projects on GitHub
ergebnis/php-cs-fixer-config
📓 Provides a configuration factory and multiple rule sets for friendsofphp/php-cs-fixer
.
Find out more at ergebnis/php-cs-fixer-config
.
ergebnis/php-cs-fixer-config-template
📓 Provides a GitHub template repository for a configuration factory and a custom rule set for friendsofphp/php-cs-fixer
.
Find out more at ergebnis/php-cs-fixer-config-template
.
ergebnis/php-package-template
📒 Provides a GitHub template repository for a PHP library, using GitHub actions.
Find out more at ergebnis/php-package-template
.
Do you find this article helpful?
Do you have feedback?
Just published: Sharing configurations for @PHPCSFixer across projects.
— Andreas Möller (@localheinz) March 10, 2023
↓https://t.co/NImnaR9OQ4