Spaces, tabs, curly braces, oh my!
Once upon a time there was a developer. The developer loved to code and liked his co-workers. However, this developer did not like the fact that his co-workers constantly ignored the coding style guide that the original team spent time to talk about and create.
What is a guy to do? Well, the obvious solution was to remind them about the style guide posted on the wiki. To make life easier, he also updated the style guide with a Subversion .XML formatting file. This made it so that all his friendly co-workers have to do is hit Shift-Command-F (yes, they are a Mac house … we’ll talk about that in another entry) to format their code in order to be in compliance with the standard …
Forward to a check-in 3 weeks later … and nothings changed. Tabs are still in place, lines run long, brackets are not on the correct line, and a half dozen other seemingly small formatting errors have crept back in. What’s a guy to do? Well an obvious choice on the PHP side of the house is to look at something like Code Sniffer.
Code Sniffer is a pear module that will sniff out PHP, Javascript, and CSS coding standard violations when passed in a coding standard and a file to process.
Coding standards? Coding standards? We don’t need no …
Before we talk more about Code Sniffer, I can already hear a few folks choking back the, “But why do we need standards?!” question … and it’s a good one.
As we learn a language and write more and more code, sometimes for one company, sometimes for many, we all start to develop our own specific brand of coding. These coding style choices rarely affect small projects or projects with only a handful of people involved but once a project starts to become large or start to have a number of hands touching them the coding styles (or the jump between them) can actually impact the maintainability of a code base.
“Huh? How does having my curly braces on one line vs. another effect maintainability.”, you say? Adopting a standard allows developers to know exactly what to expect. This increases readability of the code base and that results in faster debugging. In addition, consistent standards allows for an “expected” look and feel across multiple IDEs.
Whats so spiffy about Code Sniffer?
Code Sniffer, as mentioned earlier, detects deviations of the chosen standard. Even better, it can easily integrate with existing continuous integration systems or be used to generate reports to help coders see what issues exist and in some cases, who is causing them.
Setting up Code Sniffer
Code Sniffer is available as a pear package. You can install it using the the older pear install method:
pear install PHP_CodeSniffer
Or use the new Pyrus (Pear2) install method:
php pyrus.phar install pear/PHP_CodeSniffer
Using it for the first time
Once installed you can start using Code Sniffer right away. While it does provide you the option of setting up your own specific style guide, you can use one of the included styles to see where you stand right away. To see which styles are available, execute the following:
phpcs -i
That should return a list similar to the following:
The installed coding standards are MySource, PEAR, PHPCS, Squiz and Zend
You can test your install by selecting one of the pre-installed standards and building a report. For this example, we will first set the default coding standard to test against using the following command:
phpcs --config-set default_standard Zend
If you do not have access (root) to change this, you can pass in the standard to use by passing along, `–standard=Zend` to phpcs. Once the standard is set there are several different reporting options you can choose from. To see a list of all options type:
phpcs -h
To start, lets run a summary report against a file (replace IndexController.php in the following example with a .php file of your choice):
phpcs --report=summary IndexController.php
PHP CODE SNIFFER REPORT SUMMARY
--------------------------------------------------------------------------------
FILE ERRORS WARNINGS
--------------------------------------------------------------------------------
...Repos/trunk/www/application/controllers/IndexController.php 218 129
--------------------------------------------------------------------------------
A TOTAL OF 218 ERROR(S) AND 129 WARNING(S) WERE FOUND IN 1 FILE(S)
--------------------------------------------------------------------------------
Time: 1 second, Memory: 35.75Mb
As you can see from the example, the current IndexController falls well outside the Zend coding standard. If we wanted to see who the major offenders are we can opt to run the `svnblame` report (this is assuming you use SVN as your source control system — there is also gitblame and hgblame for those using Git or Mercurial).
phpcs --report=svnblame IndexController.php
PHP CODE SNIFFER SVN BLAME SUMMARY
--------------------------------------------------------------------------------
AUTHOR (Author %) (Overall %) COUNT
--------------------------------------------------------------------------------
jason (17.04) (97.41) 338
howard (4.52) (2.02) 7
nicoli (0) (0.58) 2
--------------------------------------------------------------------------------
A TOTAL OF 347 SNIFF VIOLATION(S) WERE COMMITTED BY 3 AUTHOR(S)
--------------------------------------------------------------------------------
Knowing who to harp on is always fun but it doesn’t really help identify what the issue really are. To get a more detailed report we need to run a `–report=full`. That will display something like the following:
FILE: ...r/Documents/Repos/trunk/www/application/controllers/IndexController.php
--------------------------------------------------------------------------------
FOUND 218 ERROR(S) AND 129 WARNING(S) AFFECTING 325 LINE(S)
--------------------------------------------------------------------------------
13 | ERROR | Protected member variable "fb" must contain a leading
| | underscore
14 | ERROR | Protected member variable "user" must contain a leading
| | underscore
15 | ERROR | Protected member variable "auth" must contain a leading
| | underscore
16 | ERROR | Protected member variable "conf" must contain a leading
| | underscore
17 | ERROR | Protected member variable "adminConfig" must contain a
| | leading underscore
18 | ERROR | Protected member variable "frontController" must contain a
| | leading underscore
... chomp ...
2011 | WARNING | Line exceeds 80 characters; contains 110 characters
2012 | WARNING | Line exceeds 80 characters; contains 93 characters
2015 | ERROR | Expected "if (...) {\n"; found "if (...)\n {\n"
2017 | ERROR | Expected "if (...) {\n"; found "if (...)\n
| | {\n"
2020 | ERROR | Expected "if (...) {\n"; found "if (...)\n
| | {\n"
--------------------------------------------------------------------------------
Time: 1 second, Memory: 35.75Mb
Alright, so now that we see the errors and warnings, what if we decide we don’t care about them? Well, the best way to get rid of them is to create your own custom standard (something I won’t cover in this quick write up). Alternatively, you can check out the standards that are being used for this check by changing the report type to `–report=source`. After running that we’ll end up with a list of standards, errors, and frequencies for each standard non-compliance we ran into.
PHP CODE SNIFFER VIOLATION SOURCE SUMMARY
--------------------------------------------------------------------------------
STANDARD CATEGORY SNIFF COUNT
--------------------------------------------------------------------------------
PEAR Control structures Control signature 185
Generic Files Line length too long 129
Generic Files Line length max exceeded 18
Zend Naming conventions Valid variable name private no underscore 12
Zend Naming conventions Valid variable name not camel caps 3
--------------------------------------------------------------------------------
A TOTAL OF 347 SNIFF VIOLATION(S) WERE FOUND IN 5 SOURCE(S)
--------------------------------------------------------------------------------
Time: 1 second, Memory: 35.75Mb
Armed with that knowledge you can manually edit the offending standards or (even better) copy them into your new standard. To learn more about creating a custom standard visit Creating coding standards for PHP CodeSniffer.
Conclusion
Some of the coding standards are very strict in relation to others. For example PHPCS will generally find a lot more issues then the Zend standard will when you first run it. If you are not going to make a custom standard, work with your fellow developers to select the standard that most fits the vision of your company while easily integrating with everyone’s current styles. Don’t worry if a few people grumble about x or y, just deciding on a standard will help you get on the right path and who knows, eventually even the grumblers might start to realize how convenient a style guide and coding standards can be.