Part of my daily work consist in assisting companies using PHP to improve their quality standards and methodologies.
Large organizations and big IT services companies I’ve worked for already have their own coding style rules with multiple severity levels specified in official documents.
These documents are supposed to establish norms for all internal and external developments. They are subject to annual reviews in which QA people meet developers to decide evolutions and parameters and severities changes: “Should we enforce this rule?” “Should we allow for weaker conditions on that?”
When I install a continuous integration system for this kind of client, the main effort goes in implementing the biggest possible part of these standards. Of course my French clients would really appreciate to find their own-defined codes and (French) messages in reports. Even more they would like to find their severity levels respected.
The tool that allows me to do this is PHP_CodeSniffer, a well established PEAR package created and maintained by Greg Sherwood. Costumization is done by creating a new PHP_CodeSniffer “Standard” and writing down some PHP classes called “Sniffers” that actually detect coding rules violations.
While I find great, and underused, the possibility to programmatically create your own sniffers, the task is not straightforward. Fortunately PHP_CodeSniffer comes with a large set of implemented sniffers, so what you normally do is to inherit from existing ones. If parameters are well separated in the parent Sniffer properties and you only need to change them, you can simply override their values.
Problems come when you want to change severities and messages, as they are someway hardcoded in the Sniffer. You’re left with the choice of duplicating the existing Sniffer’s code or to leave the original message and severity.
Note that as messages are dynamical (they contains variables, for example the name of the class under inspection) it’s impossible (or really painful and error-prone) to recover the error “a posteriori” from its message.
To overcome all these difficulties I had the idea of writing a wrapper around PHP_CodeSniffer to overload the way errors and warnings are thrown and to allow a more flexible report generation. As I’m not gifted in finding names, I called it SQLI_CodeSniffer :-)
Its main ideas can be synthesized as :
- Letting sniffers add a violation code to every error/warning they throw.
- Delay the severities and messages attribution at report time.
- Let them be taken from a configuration file matching on the newly added identifiers.
- Make it easy to add a new, user-defined type of report.
Two main advantages this new approach brings are that you can now:
- add more severities levels and filter reports up to a threshold,
- collect statistics about your violation types.
When I firstly saw the Sonar interface (look at my previous post for more) I understood that what I had done with SQLI_CodeSniffer could easily be adapted and furnish all that was needed for that kind of visualisation: just add the code violation to the report, add a category to that kind of violation in the configuration file and give that file to Sonar.
The problem with SQLI_CodeSniffer is that it is deeply tied with the original package. It’s really like a sort of big hack. Every modification done to PHP_CodeSniffer risks to make it unworkable. So I hesitated to publish it. I did indeed, but privately, here.
But this story has an happy ending, or should I say an happy new beginning.
Greg Sherwood took a look at SQLI_CodeSniffer, liked it, and decided these functionalities were worthy the main package.
So we decided to join efforts and port this and more back into PHP_CodeSniffer. All the work will be avalaible in the 1.3.0 release, we will be really careful of backward compatibility.
SQLI_CodeSniffer is dead, long live PHP_CodeSniffer!