PHP Code Sniffer — The Ins and Outs

Hi! At Behance, we use PHP Code Sniffer to enforce coding standards and rely heavily on custom sniffs. I’ve written a few, and now will share what I’ve learned.

What IS PHP Code Sniffer?

PHP Code Sniffer is a set of php scripts that allows you to tokenize files and apply a set of standards to them, thus ensuring that your codebase is clean and undeviating. The phpcs script is mostly used for PHP Files but can also tokenize Javascript and CSS files. PHP Code Sniffer is a critical development tool that creates a structured environment and strict codebase standards. PHP Code Sniffer is created and maintained by squizlabs and is Open Source! Check out their GitHub.

Why Is PHP Code Sniffer Important?

Let’s pretend we have a team of 3 people working on Fizzbuzz (It’s a hard problem) without coding standards. Here’s what we come out with:

<?php
for ($i = 1; $i <= 100; $i++)
{
if($i % 3 == 0 && $i % 5 ==0) {
echo "FizzBuzz<br />";
} else if($i % 3 == 0){
echo "Fizz<br />";
}
elseif ($i % 5 == 0)
{
echo "Buzz<br />";
} else {
echo $i."<br />";
}
}

As you can see, you have Bob who likes curly brackets on their own line, you have George who thinks every parenthesis should have a space surrounding it, and then you have Mike who just doesn’t care. This piece of code is difficult to read because of all the inconsistencies in the file and feels messy.

Let’s check out the other team of 3 who are working on FizzBuzz with a coding standard:

<?php
for ( $i = 1; $i <= 100; $i++ ) {
  if ( $i % 3 == 0 && $i % 5 == 0 ) {
echo "FizzBuzz<br />";
}
elseif ( $i % 3 == 0 ) {
echo "Fizz<br />";
}
elseif ( $i % 5 == 0 ) {
echo "Buzz<br />";
}
else {
echo $i . "<br />";
}
} // for loop through 1-100

This looks like it was written by one person and you can ensure that your whole code base will have the same result. Good practices are very difficult to maintain without a controlled environment.

How Does It Work?

PHP Code Sniffer has two php scripts — phpcs, and phpcbf. We are going to discuss mostly phpcs in this article. phpcs is the actual script that tokenizes and checks against a set of standards. phpcbf is a script that will automatically fix tokens according to the set of standards. Code standards are a group of files called sniffs. The script uses the PHP tokenizer library to “parse” your file and check against a set of sniffs, however it is not a parser, it is a tokenizer. A tokenizer takes a stream of text and breaks it into tokens, usually by looking for a certain character (tabs, spaces, new lines, etc.). A parser is something that takes the tokens and creates an abstract syntax tree out of them.

Long story short, phpcs can not detect php syntax errors.

PHP Code Sniffer will take in a line of code and tokenize it:

for ( $i = 1; $i <= 100; $i++ ) {

and break it down into these exact tokens:

T_FOR T_WHITESPACE T_OPEN_PARENTHESIS T_WHITESPACE T_VARIABLE ...

To write your own sniff you have to create a php file that implements thePHP_CodeSniffer_Sniff . This interface tells PHP_CodeSniffer to instantiate it and defines two methods that must be implemented: register and process.

The register function tells PHP_CodeSniffer what tokens to listen for and once it finds that specific token, it calls the process function with PHP_CodeSniffer_File object which has all of the token and stack pointer information of the current file being checked.

Cool! Let’s make a sniff!

To make a sniff is to decide what standard you want to implement.

Let’s make a sniff that ensure that if an expects method is being used while writing a PHPUnit Tests, it must be on the same line.

Alright, let’s write the tests.

$controller->expects( $this->once() )
->method( '_outputJson' ); // Should PASS
$controller
->method( 'read' )
->willReturn( $this->_migration ); // Should Pass

$controller
->expects( $this->once() )
->method( 'blah' ); // Should fail
$controller->method( 'blah')->expects( $this->once() ); // Should fail

And now let’s write the actual sniff file. (For more detailed instructions on how to get to this point, check out this wiki)

As you can see we implement our two required methods, register and process. In register we tell phpcs to listen for any T_STRING tokens and call process method when they’re found. The process method takes in an PHP_CodeSniffer_File object which contains all of the tokens in the file, and the stackPtr which contains the index to where T_STRING was found.

The first if statement is to check that the string we found is “expects”, so immediately throw out any other string besides expects. The next if statement checks that it is being used as a call on a variable, we do this by checking the previous token is a T_OBJECT_OPERATOR (->). Next is to check two tokens previous to where the string was found to ensure that it is a variable it is being called on. Then last but not least, we check that the variable we found is not on a different line of the string!

Thanks

This article just scratches the surface of PHP Code Sniffer, while overlooking a lot of the small implementation details on setting up, creating, and testing your own set of code standards. For more specific details please refer to the Squizlabs Wiki. As you can see this is very useful for keeping a strict and tidy code base which helps onboard new engineers. Thank you for reading and make sure to recommend/share if you think this article was helpful.


If any questions, comments, or concerns! feel free to get in touch on twitter at @bmaxhacks