PHP Code Standards
Following coding standards in PHP is now easier than ever. Let’s go over the benefits of following a coding standard, how to enforce it, and look at how modern tooling and new features in IDE’s like PHPStorm makes it nicer than ever before.
Why Follow a Coding Standard?
- Stop Wasting Time
If you’ve ever worked with another developer or worked on a team, no doubt you’ve debated coding styles. Focus on what’s important (getting things done) and stop debating:
– Tabs vs spaces
– camelCase vs snake_case
– Opening brackets {} on new line or same line
– Control structure format
– TRUE/FALSE/NULL vs true/false/null
– Spacing that could go anywhere and everywhere
– … the list is never ending. - More Readable Code
Easier to read code comes from using a consistent code style. Your brain isn’t distracted by the personal preferences of the previous developer. In Jason McCreary’s book Basecode, he does an excellent job of explaining a concept which Kevlin Henney has coined “visual honesty”. It’s the concept that you should be able to generally tell what’s happening in a function just by the shape of the code blocks. He illustrates this by showing that if all the characters were replaced with X’s, when code is formatted properly, you can still recognize what’s happening. I had noticed the benefits of this before, but had a hard time putting it into words; what an excellent way to demonstrate it! - Save Money
Time is money, whether it’s your time or the company’s. Save time in both new developer on-boarding, as well as on code maintenance. New hire ramp-up time can be reduced if your codebase is in a popular format. It increases the chances the new developer has previous experience developing, reading and writing code in that format. For maintenance, code reviews are simpler, as there are less stylistic changes from developer to developer. As code reviews and new hires are a constant, this savings in developer time translates to real cost savings for the business over time.
EditorConfig
At the very least, a project in any language should add an EditorConfig. EditorConfig is a widely adopted open standard that helps maintain general coding styles. It’s a file which sits in the root of your project that many IDE’s will automatically (or with a plugin) read settings to set tabs vs spaces, tab length to 4 spaces, etc. PHPStorm now has EditorConfig support built-in since PHPStorm 2019.2, VS Code has a plugin, and so does almost all code editors.
EditorConfig can only specify generic coding style settings, for the rest of the article we’ll look at standards and tools that go a lot further, specific to PHP.
PSR-12
In 2009, all the popular frameworks came together (PHP-FIG) and agreed on common coding standards PSR-1 and PSR-2. Since then, PSR-2 (which builds upon PSR-1) had become the defacto coding standard in PHP, which is nice because you know any framework or 3rd-party php package you come across will follow the same coding style.
In August 2019, PSR-12 was approved, adding rules for new language features introduced in PHP 7. PSR-12 is now the recommended standard to follow.
But We Can’t Follow PSR-12 Because Of ________
Here’s some of the popular reasons holding team’s back from following PSR-12:
“We have so much code already, it’d be too much work to convert it all.”
“We have certain folders we can’t (or don’t want to) touch.”
“There’s certain rules in PSR-12 that would break our code”
“There’s rules in PSR-12 my team strongly disagrees with.”
Historically, it’s been difficult to perform large stylistic changes on an existing code base. Luckily there are tools which can convert all your files for you! We’ll walk through these tools in “Linters”.
There might be disagreement around the merit of specific rules within a coding standard. The tooling today easily addresses these concerns. It’s super easy to extend the PSR-12 coding standard and exclude certain folders or rules. We’ll walk through how to do this in Creating a Configuration File.
Linters
PHP_CodeSniffer
PHP_CodeSniffer is a linter command line tool for following PHP coding standards. You can install it globally so that from any project you can run the phpcs
command to analyze files and phpcbf
to fix them. Starting in version 3.5 has support for PSR-12.
Install PHP_CodeSniffer (Globally)
// Install globally composer global require "squizlabs/php_codesniffer=*"
// Set the coding standard phpcs --standard=PSR12
// Scan a specific file
phpcs app/Controllers/HomeController.php
// Scan all files phpcs .
// Fix a specific file
phpbf app/Controllers/HomeController.php
// Fix all files
phpcbf .
Install PHP_CodeSniffer (Project Dependency)
Having it installed globally is handy, the command is short so no matter what project you jump into it’s easy to remember. But I recommend also installing it as a composer dev dependency in your project. This way, no matter what, it’s installed for all your teammates and you all have the same version.
// Install locally composer require --dev "squizlabs/php_codesniffer=*"
Then you can run it the same way as demonstrated globally above, you just need to specify the vendor bin path where composer installs it to.
// Scan
vendor/bin/phpcs --standard=PSR12 app/Controllers/HomeController.php
// Fix vendor/bin/phpcbf --standard=PSR12 app/Controllers/HomeController.php
We can avoid potentially forgetting to pass --standard=PSR12
by creating a phpcs.xml configuration file like we’ll demonstrate below.
If you find it annoying to type out the entire vendor path or have a hard time remembering the vendor path, maybe create a composer run-script which we’ll also go over below.
Even so, I’ll be honest, I usually just use the globally installed version; it’s easier to just type phpcs
, and PHP_CodeSniffer doesn’t change too much from version to version. But I install it as a dev dependency anyway so that it’s there if I need it to run it on a server or another system. Plus there’s an added benefit that by setting it as a dev dependency and creating the composer run-script, our teammates IDE’s can set the coding standard automatically for them.
Create a phpcs.xml Configuration File
Like I said above, you may Extend PSR-12 if you want to exclude files or folders, or exclude certain rules. By placing a phpcs.xml
file at the root of your project, anyone who runs phpcs
doesn’t have to worry about passing any arguments to set the coding standard to PSR-12 or any custom settings for your project. PHP_CodeSniffer will automatically read them from this config file instead.
As a simple example, here’s how you create a custom standard that extends PSR-12 but excludes the 120 character line length limit, adds a rule to disallow long array syntax, and ignores a /views/ folder.
phpcs.xml
<?xml version="1.0"?>
<ruleset name="My Company Coding Standard">
<description>PSR12 with tweaks.</description>
<rule ref="PSR12">
<exclude name="Generic.Files.LineLength.TooLong"/>
</rule>
<rule ref="Generic.Arrays.DisallowLongArraySyntax"/>
<exclude-pattern>*/views/*</exclude-pattern>
</ruleset>
Here’s a more complex example: https://github.com/squizlabs/PHP_CodeSniffer/blob/master/phpcs.xml.dist
And full documentation can be found here: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-Ruleset
Create a Composer Script
Remembering the path to the local installation of phpcs
and typing it out every time can get tedious, not to mention remembering to pass the flag for what standard to use if you don’t need a phpcs.xml
, so you can create a composer script to make it easier:
"scripts": {
"phpcs": "vendor/bin/phpcs --standard=PSR12 app"
}
Then you only have to run:
composer phpcs
This has 2 additional benefits:
- PHPStorm 2020.1 will provide play buttons to run composer run-scripts with just one click.
- PHPStorm can automagically set your standard in PHPStorm.
PHP CS Fixer
PHP CS Fixer is an alternative linter to PHP_CodeSniffer. It doesn’t have PSR-12 yet, but they are working to add PSR-12 support. It does, however, include all the other same popular standards that PHP_CodeSniffer supports, like PSR-12’s predecessor PSR-2 and others.
As well, PHP CS Fixer also includes support for the Symfony coding standard. It takes the PSR-2 coding standard (PSR-12 soon) and builds upon it with coding opinions common in their framework’s community. I personally really like it, except I do tweak a couple settings. I like to turn off yoda_style, and turn on a couple handy fixers that PHP_CodeSniffer doesn’t have, like sorting import statements alphabetically, and removing unnecessary fully qualified class names.
Unlike PHP_CodeSniffer where you set the standard/rules in an xml file, for PHP CS Fixer you set them in a PHP file (either .php_cs or .php_cs.dist). Here’s an example for PHP CS Fixer on how to set the standard as the Symfony coding standard and make the other tweaks I just mentioned:
.php_cs.dist
<?php
$finder = PhpCsFixer\Finder::create()
->exclude([
'views',
])
->in(__DIR__);
return PhpCsFixer\Config::create()
->setRules([
'@Symfony' => true,
'array_syntax' => ['syntax' => 'short'],
'concat_space' => ['spacing' => 'one'],
'yoda_style' => false,
'fully_qualified_strict_types' => true,
'ordered_imports' => true,
'phpdoc_align' => false,
'phpdoc_separation' => false,
])
->setFinder($finder);
Documentation for these and other settings can be here: https://github.com/FriendsOfPHP/PHP-CS-Fixer#config-file
IDE Support
PHPStorm
PHPStorm + PHP Linters = 🔥. IntelliJ has made linters a first class citizen in their PHPStorm IDE. There’s no plugin needed. You can utilize PHP_CodeSniffer or PHP CS Fixer right inside the IDE so you don’t have to run commands on the command line. What’s nice about this integration is that it will help you follow the PSR-12 coding standard in real-time as you write code.
Here’s the 3 steps you’ll need to do in order to get PHPStorm setup with either PHP_CodeSniffer or PHP CS Fixer:
- Set the “Code Style”
By setting the code style we make sure that when you reformat entire classes, generate code, or refactor code, PHPStorm will follow PSR-12 when it rewrites your code for you. Starting in PHPStorm 2019.3, PSR-12 is available as one of the built-in code styles to pick from.
Preferences > Editor > Code Style > PHP > “Set from…” > Predefined Style > PSR12
- Turn on “Code Quality Tools”
We need to validate that PHPStorm knows where the linter is installed for when it needs to use it to lint your code.
Preferences > Languages & Frameworks > PHP > Quality Tools > Code Sniffer
Click the ellipsis (…) and use the validate button to make sure it can detect where PHP_CodeSniffer is installed.
- Turn on “Inspections”
By turning on Inspections for the linter, PHPStorm will put a squiggly line below any code for any issues the linter detects. Opening the intention actions menu on an inspection will even provide an action to fix the issue for you starting in PHPStorm 2019.1 for PHP_CodeSniffer (and PHPStorm 2018.3 for PHP-CS-Fixer). You can see this in action in the gif at the top of this article!
Preferences > Editor > Inspections > PHP > Quality Tools > PHP_CodeSniffer Validation ✅
Set the Coding Standard Automatically for Teammates
PHPStorm recently made it super easy to have the coding standard set automatically for all your team members by simply adding a line to your composer.json:
Note: You’re teammates must use Composer through PHPStorm (eg. Tools > Composer > Install/Update) for it to automatically set the path and turn on the inspections for them.
Visual Studio Code
PHPStorm is probably the most popular IDE for PHP, but Visual Studio Code (VS Code) is becoming a very popular (and free) IDE for PHP developers. You can install the phpcs plugin for PHP_CodeSniffer integration or the php cs fixer plugin for PHP CS Fixer integration.
Sublime Text, Vim, Atom & Others
Sublime Text has sublime-phpcs. Vim has Syntastic or Ale. Atom has a linter-phpcs package. As for PHP CS Fixer, they have a list of plugins for various editors right on their Github readme.
Taking It a Step Further
So now you’ve got linting working on the command-line, you’ve reformatted your codebase to PSR-12, and your IDE of choice is setup to lint in real-time! Now how do you keep your codebase PSR-12 compliant? Ever opened up a class to find others had committed a bunch of code that doesn’t follow PSR-12? Do you find yourself having to run phpcs
across the whole codebase every couple months?
In my next blog post we’ll go over how to make sure PSR-12 errors never makes it into master again. I’ll go a step further and show how you can catch PSR-12 violations before they even make it into a commit! Subscribe via RSS, or follow me on twitter to find out about the next blog post comes out!
Also published on Medium.