Last time we looked at some sample CodeSniffer reports and in the source report we saw that the Zend standard was also reporting errors from other standards.
$ phpcs --report=source --standard=Zend ./_rr
PHP CODE SNIFFER VIOLATION SOURCE SUMMARY
--------------------------------------------------------------------------------
STANDARD CATEGORY SNIFF COUNT
--------------------------------------------------------------------------------
Zend Files Line length 92
Generic White space Disallow tab indent 65
Zend Naming conventions Valid variable name 59
PEAR White space Scope closing brace 33
PEAR Functions Function call signature 26
PEAR Control structures Control signature 12
PEAR Files Line endings 11
PEAR Functions Function call argument spacing 5
Generic PHP Disallow short open tag 1
Zend Files Closing tag 1
--------------------------------------------------------------------------------
A TOTAL OF 305 SNIFF VIOLATION(S) WERE FOUND IN 10 SOURCE(S)
--------------------------------------------------------------------------------
Each CodeSniffer standard is comprised of rules or sniffs. A standard can contain a sniff from other standards.
This allows us to quickly and easily create our own custom standard by leveraging those rules that are already contained in existing standards.
To find out what we have available to use, we can looking for all the files that end in Sniff.php within the Standards folder. We can see we have 167 sniff available to use already (with version 1.2.0a1 anyway).
Full list of available Sniffs
cd {your pear path}/PHP/CodeSniffer/Standards
$ find ./ -name "*Sniff.php" -and -not -name "Abstract*"
Clicking here to see the full list of available Sniffs.
Some of these Sniffs are self explanatory some are less so, and would need a cursory glance at the code to see what they are checking for.
Luckily most of the classes are well documented (as the PHPCS standard dictates!) so looking at the class phpdoc comment usually tells what the sniff is looking for.
Something to note is that you will find some of the sniffs are mutually exclusive:
e.g.
./Generic/Sniffs/Formatting/NoSpaceAfterCastSniff.php
./Generic/Sniffs/Formatting/SpaceAfterCastSniff.php
./Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php
./Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php
Writing the standard
So to start with we need to come up with a name for the standard.
So for this example I’m going to use KingKludge.
Now I prefer to develop in my home dir, but to get this sniff recognised you will need to have the standard available in {your pear path}/PHP/CodeSniffer/Standards/.
So I symlink my standard into the pear path, but you could work directly in the pear folder.
$ mkdir KingKludge
$ ln -s KingKludge {your pear path}/PHP/CodeSniffer/Standards/KingKludge
Then we need to create the standard file. Which follows the naming convention {standard}CodingStandard.php so we end up with the following file.
KingKludgeCodingStandard.php
The underscores in the class name are important as the autoload function splits the path at underscores, so if you miss-type one of the path parts you will get a fatal error when the class attempts to load.
Assuming that you did have your class in the correct folder you can do run.
$ phpcs -i
And you should see your new standard is listed as available for use.
As a timesaving tip, to stop us from having to type the standard name every time you can run CodeSniffer run the following command.
$ phpcs --config-set default_standard KingKludge
Now unless we override with the --standard
switch CodeSniffer will default to using the KingKludge standard.
Adding some rules
So now we have a new standard but it doesn’t do anything yet, as it has no rules to apply.
We have two methods in the class to define the rules or sniffs getIncludedSniffs()
and getExcludedSniffs()
. Not unsurprisingly these methods should return an array of the sniffs to include or exclude.
If we decided we wanted to make life easy for ourselves and base our standard on someone else’s standard, we can quite simply include all of their standard and then swap out the sniffs we don’t want for others we do.
For example, taking the Squiz coding standard.
public function getIncludedSniffs()
{
return array(
'Squiz',
);
}
Now say we want to swap the BSD style bracing rule for K&R style braces, and we don’t want the CodeAnalyzer rule to run either.
So we add the K&R braces Sniff to our include and add the CodeAnalyzer and BSD braces sniffs to the exclude.
public function getIncludedSniffs()
{
return array(
'Squiz',
'Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php',
);
}
public function getExcludedSniffs()
{
return array(
'Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php',
'Zend/Sniffs/Debug/CodeAnalyzerSniff.php',
);
}
That seems easy enough!
So now you can see how easily you can create your own standards by picking as few or as many sniffs as you want from existing standards.
Next time, understanding the internals of CodeSniffer and how it works.