CodeSniffer Part 5: Writing an examples CodeSniffer Sniff

There has been a significant delay between the original posts and this final post in the initial CodeSniffer series, for which I apologise. This delay is mainly due to my recent workload increase, and the happy news that my wife is pregnant coupled with the brief flutter of nesting activity increase at home.

In the last post we looked at the internals of CodeSniffer and how the processing of files is done. This time we will look at how an individual Sniff is constructed.

Sniff Basics

  • Each Sniff is a PHP class.
  • Each class consist of a minimum of two methods.
    • A register method, that returns an array of tokens that the Sniff is interested in.
    • And a process method that is executed each time that token is encountered.
  • Each Sniff class lives inside a Standard.
    • Each Sniff lives inside a subfolder “Sniffs” under the standard
    • Each Sniff lives inside a subfolder of “Sniffs” containing themed Sniffs
  • Each Sniff class must adhere to the naming convention.

Starting a Sniff

Let’s take a look at an example Sniff. For instance a Sniff designed to check that our PHP code has no extraneous whitespace outside of our PHP code, that could cause a PHP error should we subsequently send headers to the browser.

First of all we create a class and decide on a name for it.

As CodeSniffer uses an autoloader that loads the class’ file and path based on the class name we have to stick to a specific naming convention.

class KingKludge_Sniffs_PHP_NoExtraneousWhiteSpaceSniff
implements PHP_CodeSniffer_Sniff
{}

equates to a path of:

{CodeSniffer}/Standards/KingKludge/Sniffs/PHP/NoExtraneousWhiteSpaceSniff.php

where {CodeSniffer} is your CodeSniffer install path.

Secondly, inside our new class we must define our register method:

public function register()
{
	return array(
		T_OPEN_TAG,
		T_CLOSE_TAG,
		);
}

As we want to check for whitespace before or after our PHP declarations, we state that this sniff is interested in PHP open and close tags.

Thirdly, we must define our process method:

public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
{

}

As you can see, our process method is passed some parameters.

These are $phpcsFile which is PHP_CodeSniffer_File object, containing the file being processed and $stackPtr an integer value pointing to CodeSniffer’s current place in the file.

View the empty standard file on GitHub

Now on to the actually code in our Sniff.

As our proposed Sniff is going to look for whitespace being output before our page is ready to be rendered, we are interested in whitespace that occurs before the opening PHP tag or after the closing PHP tag.

We are only interested in whitespace, any HTML or other markup is okay.

So we can see if our pointer is at the beginning of the file, if so, drop out of the process.

$tokens = $phpcsFile->getTokens();
if (T_OPEN_TAG === $tokens[$stackPtr]['code'])
{
	if (0 === $stackPtr)
	{
		return;
	}
}

The getTokens() command returns all of the tokens for the current file in an associative array. (in case you didn’t realise).

The rest should be self explanatory.

We can also do a similar check for a PHP close tag

if (T_CLOSE_TAG === $tokens[$stackPtr]['code'])
{
	$content = $tokens[$stackPtr]['content'];
	if (
	    false === isset($tokens[($stackPtr + 1)]) &&
	    trim($content) === $content
	   )
	{
		return;
	}
}

View the basic standard file on GitHub

This entry was posted in Development, PHP, Software and tagged , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *