Sharing PHPCS Rules Across Projects and Teams

Published on by

Sharing PHPCS Rules Across Projects and Teams image

PHPCS is an open-source CLI tool that detects code style violations of a defined coding standard, and also provides automatic fixes for automatically fixable rules. I want to convince you that even if you use Pint or PHP-CS-Fixer directly, you should still consider adding PHPCS to your repertoire.

Defining PHPCS rules across multiple projects in a team setting is tedious, and rule drift is bound to happen between projects. You'll likely want to enforce consistent rules across your projects without much thought or effort.

At the end of this tutorial, you'll know how to create an organization ruleset you can use to quickly lint all your PHP projects.

In Part 1 of this series, you learned how to Use PHP Codesniffer With Laravel projects. This tutorial will move the ruleset we created in a Laravel project to a dedicated Composer package.

Background

You might ask, "why would I use PHPCS when we have Laravel Pint and PHP CS Fixer?" Instead of considering these tools as competitors, consider them complementary tools that each provide unique, valuable code style suggestions and fixes. PHPCS is a linter, and PHP-CS-Fixer is a fixer.

Indeed, these types of tools overlap: PHP-CS-Fixer has linting capabilities using the --dry-run feature. PHPCS has a phpcbf CLI tool that automatically fixes PHPCS sniff violations. However, phpcbf does not fix every single available rule.

For example, you can configure PHPCS to detect and report line length violations; however, PHPCS cannot automatically fix these violations since the tool cannot determine how you would like to break up long lines:

The screenshot illustrates line length configuration that warns when a line exceeds 120 characters and warns for lines that exceed 80 characters but are still within the maximum threshold of 120 characters. This can be useful to keep your code healthy and lint things like line length.

Getting Started

We'll need to create a new PHP composer package to create a custom Ruleset that you can reuse on all your projects. PHPCS needs to know about these rulesets though, so we will use the Composer Installer package which makes it easy to install coding standards via Composer.

Before we get to that, let's create a package and initialize Git and Composer:

mkdir phpcs
cd phpcs
git init
composer init

Once you run composer init, Composer will prompt you to define things like your package name. At least fill out the package name, optionally the description, and finish the prompts. We will require dependencies manually, so don't worry about installing them interactively.

To ease detecting PHPCS standards from composer packages, we now need to install the Composer Installer package:

composer require --dev \
dealerdirect/phpcodesniffer-composer-installer

The composer installer also requires that you define the type property with phpcodesniffer-standard. The Composer Installer plugin searches for rulesets using the type property in all of your project's installed Composer packages.

In the end, your composer.json file should look something like the following:

{
"name": "bitpressio/phpcs",
"type": "phpcodesniffer-standard",
"authors": [
{
"name": "Paul Redmond",
"email": "paulrredmond@gmail.com"
}
],
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^1.0"
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}

We have everything we need to define our Composer package, and all we need to do to get it working is define our ruleset.

Defining the Ruleset

Our Composer package will contain our ruleset.xml file that we will install in all of our projects. I named my ruleset Bitpress, so I need to create a folder in my project that will house the ruleset:

mkdir Bitpress
touch Bitpress/ruleset.xml

We created a Ruleset in Part 1 of this series, so add the following contents to ruleset.xml, replacing values for whatever you called your ruleset:

<?xml version="1.0"?>
<!-- @see https://pear.php.net/manual/en/package.php.php-codesniffer.annotated-ruleset.php -->
<ruleset name="Bitpress PHPCS Rules">
 
<description>PHPCS ruleset for Bitpress</description>
 
<!-- Use colors in output -->
<arg name="colors"/>
 
<!-- Show progress of the run -->
<arg value="p"/>
 
<!-- Show sniff codes in all reports -->
<arg value="s"/>
 
<!-- Our base rule: set to PSR12 -->
<rule ref="PSR12">
<exclude name="PSR12.Traits.UseDeclaration.MultipleImport" />
<exclude name="PSR12.Operators.OperatorSpacing.NoSpaceBefore" />
<exclude name="PSR12.Operators.OperatorSpacing.NoSpaceAfter" />
</rule>
 
<rule ref="Generic.Files.LineLength">
<properties>
<property name="lineLimit" value="80"/>
<property name="absoluteLineLimit" value="120"/>
</properties>
</rule>
 
<rule ref="PSR1.Methods.CamelCapsMethodName.NotCamelCaps">
<exclude-pattern>tests/</exclude-pattern>
</rule>
 
<exclude-pattern>*/.phpstorm.meta.php</exclude-pattern>
<exclude-pattern>*/_ide_helper.php</exclude-pattern>
<exclude-pattern>*/*.blade.php</exclude-pattern>
<exclude-pattern>*/autoload.php</exclude-pattern>
<exclude-pattern>*/vendor/*</exclude-pattern>
 
</ruleset>

Our ruleset will not include any custom sniffs, but we will define our preferred setup based on the built-in PSR12 ruleset.

We have everything we need to start using our custom ruleset! Once you publish your composer package, you can require it as a --dev dependency.

Setting Up the Ruleset in a Project

Once your package is published as a Composer package, you can install it in a project like so:

composer require --dev bitpressio/phpcs

The Composer Installer dependency will ask for permission to execute code so that it can detect and install found standards in Composer packages. Select y to enable the plugin:

At this point, we installed our custom Ruleset, and we can verify using the following command:

vendor/bin/phpcs -i
The installed coding standards are
MySource, PEAR, PSR1, PSR2, PSR12, Squiz, Zend,
Bitpress and VariableAnalysis

The --show-info flag can show us more information:

vendor/bin/phpcs --config-show
Using config file: /Users/paul/code/sandbox/bitpress-phpcs/vendor/squizlabs/php_codesniffer/CodeSniffer.conf
 
installed_paths: ../../bitpressio/phpcs,../../sirbrillig/phpcs-variable-analysis

Finally, we can make our ruleset the default with the following:

vendor/bin/phpcs --config-set default_standard Bitpress

We could have each developer manually set our rulesets as the default; however, using composer.json we can trigger it automatically with the following:

"scripts": {
"post-package-install": "vendor/bin/phpcs --config-set default_standard Bitpress"
}

If we rerun our command, our ruleset should be the default now:

vendor/bin/phpcs --config-show
...
default_standard: Bitpress

We are almost done, but we have a few minor tweaks to make to finish up our installation.

Defining a Project Ruleset Configuration

We have our ruleset installed and set as the default standard. However, if we run phpcs we will get the following message:

vendor/bin/phpcs
ERROR: You must supply at least one file or directory to process.
 
Run "phpcs --help" for usage information

Though our ruleset is the default, we still need to provide configuration to instruct PHPCS which files and folders to lint. Let's create a phpcs.xml in the root of a project:

<?xml version="1.0"?>
<!-- @see https://pear.php.net/manual/en/package.php.php-codesniffer.annotated-ruleset.php -->
<ruleset name="My App">
<file>app</file>
<file>tests</file>
 
<rule ref="Bitpress"></rule>
</ruleset>

If you run phpcs in your project (I tested this out in a new Laravel app), PHPCS will lint files in app/ and tests/ and should output some warnings about line length. Feel free to configure these paths to your liking.

Wrap Up

On our whirlwind tour of PHPCS rulesets, we published a composer package containing a custom Ruleset that we can share across our organization. If you want consistent linting across multiple projects, hopefully this approach might come in handy.

Paul Redmond photo

Staff writer at Laravel News. Full stack web developer and author.

Cube

Laravel Newsletter

Join 40k+ other developers and never miss out on new tips, tutorials, and more.

image
No Compromises

Joel and Aaron, the two seasoned devs from the No Compromises podcast, are now available to hire for your Laravel project.

Visit No Compromises
Laravel Forge logo

Laravel Forge

Easily create and manage your servers and deploy your Laravel applications in seconds.

Laravel Forge
Tinkerwell logo

Tinkerwell

The must-have code runner for Laravel developers. Tinker with AI, autocompletion and instant feedback on local and production environments.

Tinkerwell
No Compromises logo

No Compromises

Joel and Aaron, the two seasoned devs from the No Compromises podcast, are now available to hire for your Laravel project. ⬧ Flat rate of $7500/mo. ⬧ No lengthy sales process. ⬧ No contracts. ⬧ 100% money back guarantee.

No Compromises
Kirschbaum logo

Kirschbaum

Providing innovation and stability to ensure your web application succeeds.

Kirschbaum
Shift logo

Shift

Running an old Laravel version? Instant, automated Laravel upgrades and code modernization to keep your applications fresh.

Shift
Bacancy logo

Bacancy

Supercharge your project with a seasoned Laravel developer with 4-6 years of experience for just $2500/month. Get 160 hours of dedicated expertise & a risk-free 15-day trial. Schedule a call now!

Bacancy
LoadForge logo

LoadForge

Easy, affordable load testing and stress tests for websites, APIs and databases.

LoadForge
Paragraph logo

Paragraph

Manage your Laravel app as if it was a CMS – edit any text on any page or in any email without touching Blade or language files.

Paragraph
Lucky Media logo

Lucky Media

Bespoke software solutions built for your business. We ♥ Laravel

Lucky Media
Lunar: Laravel E-Commerce logo

Lunar: Laravel E-Commerce

E-Commerce for Laravel. An open-source package that brings the power of modern headless e-commerce functionality to Laravel.

Lunar: Laravel E-Commerce
DocuWriter.ai logo

DocuWriter.ai

Save hours of manually writing Code Documentation, Comments & DocBlocks, Test suites and Refactoring.

DocuWriter.ai
Rector logo

Rector

Your partner for seamless Laravel upgrades, cutting costs, and accelerating innovation for successful companies

Rector

The latest

View all →
Non-backed Enums in Database Queries and a withSchedule() bootstrap method in Laravel 11.1 image

Non-backed Enums in Database Queries and a withSchedule() bootstrap method in Laravel 11.1

Read article
Laravel Pint --bail Flag image

Laravel Pint --bail Flag

Read article
Laravel Herd for Windows is now released! image

Laravel Herd for Windows is now released!

Read article
The Laravel Worldwide Meetup is Today image

The Laravel Worldwide Meetup is Today

Read article
Cache Routes with Cloudflare in Laravel image

Cache Routes with Cloudflare in Laravel

Read article
Learn how to manage timezones in your Laravel Apps image

Learn how to manage timezones in your Laravel Apps

Read article