Maintaining consistent coding style in PHP projectsMaciej Lewkowicz
Reading Time: 6 minutes
Have you ever wondered how it's done that Magento core code—or Zend, Symfony or many other PHP projects for that matter—just looks good, especially when compared to custom or 3rd-party code? The key factor here is maintaining consistent coding style. And while there's no substitute for a thorough code review, in this article I'd like to show you a few tools that will help you with that.
The problem of language flexibility
In PHP (and other languages) there are different ways of doing the same thing. Take creating an array. Historically you'd use the
array() function to do that, but as of PHP 5.4 you can go for short syntax:
Back in the days the only way of creating an array in PHP would be the following:
Now you can use a more concise syntax:
Now, you’d probably be right thinking that this isn’t big deal. That’s until someone starts mixing the two like so:
Still, a bit annoying at most, but hardly a blocker.
Let’s try a more complex example: imagine the number of ways there are to write a simple function with a single if statement:
You can omit
else without changing the function's behaviour. Then you can also remove the curly braces and have:
Or maybe you'd like to drop
if altogether and use a ternary operator instead:
And how about Yoda conditions and replacing
$sun->isShining() === true with
true === $sun->isShining()?
This gives us 6 different ways of writing one of the simplest possible pieces of code imaginable. Not considering placement of curly braces or spacing around parentheses and operators.
Of course, any project sooner or later will need some more complex logic. In that case using multiple ways to express a single concept will make the code hard to read and understand.
“Indeed, the ratio of time spent reading vs. writing is well over 10:1. We are constantly reading old code as part of the effort to write new code.
Because this ratio is so high, we want the reading of code to be easy, even if it makes the writing harder. Of course there's no way to write code without reading it, so making it easy to read actually makes it easier to write.”
As developers we spend lots of time reading source code. One way we could make this task easier for our teammates and for ourselves is to make sure the code is written in a consistent way.
A side benefit of maintaining consistent codebase is that it shows authors’ attention to detail and is a good indicator of high quality of a project.
Coding Standards: consistent coding style, codified
Coding standards are all about making the code easier to read and understand. While most coding standards I’ve seen focus mainly on formatting, in this article I use this term (interchangeably with “coding style”) in a broader meaning which also encompasses some design patterns and general best practices.
Okay, but how to define a coding standard for a project? My best advice is to use whatever the framework uses. This way the code should feel familiar to any developer who has experience with given platform. And the bonus is that you'll avoid endless discussions on whether tabs or spaces are better for indentation.
As the author of JSLint put it:
“The place to express yourself in programming is in the quality of your ideas and the efficiency of their execution. The role of style in programming is the same as in literature: It makes for better reading. A great writer doesn't express herself by putting the spaces before her commas instead of after, or by putting extra spaces inside her parentheses. A great writer will slavishly conform to some rules of style, and that in no way constrains her power to express herself creatively.”
Once you decide on which coding standard to use, the next step would be to make sure the code complies with it—ideally in an automated way. With a couple of simple tools and well-defined rules you'll have one less thing to think about when working on the code. Although there are many others, in this article I’ll focus on PHP_CodeSniffer and PHP Mess Detector (and EditorConfig), as those are the ones I use everyday. Here's how to set everything up for a Magento-based project.
The common part
I almost always start configuring the project with creating an .editorconfig file:
This little file instructs your IDE to:
- Use 4 spaces for indentation—both PSR-2 and the old Zend coding standard suggest this,
- Use Unix-like newline character—since the code will most likely run on some flavour of Linux,
- Leave an empty line at the end of the file—to avoid complaints from different Unix tools (including git),
- Remove any extra whitespace (spaces or tabs) at the end of each line—it's almost never there on purpose and can be annoying.
Some IDEs support EditorConfig out-of-the-box, for others you'll need a plugin. I find it to be a sane starting point for just about any project, but of course you can extend this config to match any preference or need.
The interesting part
With EditorConfig taking care of basic formatting, we can now focus on some more advanced stuff and configure PHP-specific tools to keep our coding style in check.
We’ll use PHP_Codesniffer and PHP Mess Detector. Additionally the following packages will come in handy:
- Magento Expert Consulting Group Coding Standard
- Magento Extension Quality Program Coding Standard
- ExtDN PHP_CodeSniffer rules (for Magento 2 only)
- PHP_CodeSniffer Standards Composer Installer (this little package makes handling multiple PHPCS rulesets much easier)
You can install both PHPMD and PHPCS with its plugins via Composer. Though everything can be installed globally, I suggest adding your tools to project’s composer.json to avoid compatibility issues.
Note: If you encounter an issue with any of the rulesets (or PHPCS itself) please refer to appropriate project’s repository for help.
Magento 1.x: how it used to be
Having everything installed, let’s get to configuration. We’ll start with PHP_CodeSniffer, which accepts XML configuration files.
An example of dev/phpcs/ruleset.xml would be:
All that’s left to do is to point PHPCS to the ruleset.xml file and it’ll automatically warn you about not only formatting, but also security, performance, and maintainability issues.
Note that MEQP1 ruleset references the whole Zend coding standard, so there’s no need to include it separately.
Good, we now have our code check against some best practices for Magento. But there’s no reason to stop here! Let’s take our coding standard one level higher with the following PHPMD ruleset:
While PHPCS focuses primarily on formatting and framework-specific patterns, PHPMD covers some more general good practices, like class and method size and complexity, proper naming, and detects some hard-to-read patterns.
Unfortunately, it’s virtually impossible to follow all best practices that PHPMD can check, hence the proposed configuration focuses on the basics. It’s a good starting point and—possibly after minor tuning—will prove itself valuable for maintenance of even old Magento 1 projects.
Magento 2.x: how it is now
Even though the coding standard is pretty well outlined in Magento 1, it’s Magento 2 where you get full benefit of having PHPCS and PHPMD properly setup. Let’s dive straight into the rulesets!
An example of dev/phpcs/ruleset.xml would be:
At first glance this ruleset is not too unlike the one we’ve just seen for Magento 1. Don’t be fooled by superficial similarity though—with Magento 2 coding standards and best practices being better defined than previously, both EcgM2 and MEQP2 include some additional checks. Moreover a new player has entered the game: Magento Extension Developers Network (ExtDN) who aim to provide even more rules you can use on your code.
Note that MEQP2 ruleset already includes PSR2 coding standard, so there’s no need to include it separately.
Going further, an example of dev/phpmd/ruleset.xml would be:
With Magento 2 it’s finally possible to go all-in on PHPMD. This means checking all the stuff that Magento 1 ruleset would check and more—such as possible SRP violations, static access or unused code.
You may find the proposed ruleset to be a bit too strict for your particular project and coding style, yet I’d strongly suggest starting with this configuration and relaxing it when necessary—as opposed to starting with a pretty lax ruleset for Magento 1 and adding more checks later.
As often with tools—your mileage may vary.
When introducing a formalized coding standard on a project, consider the impact it may have. To benefit fully from using the tools discussed here, you need to make sure everyone on the team is on board and understands what the standards are for.
Also bear in mind that while you can (and certainly should in some cases) use comments to suppress both PHPCS and PHPMD warnings, but overly strict rulesets will likely result in you and your teammates marking whole blocks or even files as ignored, which defies the purpose of having a ruleset in the first place.
Maintaining consistent coding style makes developing software much easier. Not having to worry about how to write the code frees your mind to let you focus on solving the problem at hand.
Even though some standards are difficult to get used to, some are controversial and some outright weird, the benefit of having a single, well-defined way of expressing yourself as a developer is hard to overvalue.
If you and your team don’t have a defined coding style—it’s worth adopting one. And if you do, it’s worth revising it from time to time. Standards evolve (luckily in PHP realm not as fast as in JS world) but the right tools make it a breeze to follow them.
Have fun coding!