Official website for Web Designer - defining the internet through beautiful design
FOLLOW US ON:
Author: Steve Jenkins
8th January 2013

Check your PHP Code with CodeSniffer

Ensure your code meets standard coding guidelines using the impressive PHP CodeSniffer tool

Check your PHP Code with CodeSniffer

Code, like any language, is something that should be easily readable by those who can understand it, and ideally, it should still be vaguely understandable by anyone who isn’t fluent in all things ‘dev’.

This stands particularly true as we all have our own way of writing – our own syntax, layouts and formatting preferences, and our own personal ticks and idiosyncrasies. This is normally easy to manage if working on your own, but as soon as you share code with a team of developers, each with their own style and way of doing things, it can get messy pretty quickly.
In this tutorial we will take a look at PHP CodeSniffer, an open-source tool that uses a number of standard coding guidelines against which you can test your code. You can also extend it to create your own custom standard guidelines. May your code be formatted and indented to pixel perfection!

Download PEAR

PEAR is a framework and distribution system for reusable PHP components, and stands for PHP Extension and Application Repository, and PEAR will help us download and configure the CodeSniffer package. Download the PEAR phar (PHP archive). Using Terminal, navigate into your home directory and execute a curl request to download the required application archive files.

001 sudo curl http://pear.php.net/go-pear.phar > go-pear.phar

PEAR installation

Check your PHP Code with CodeSniffer
With the .phar package downloaded into your home directory, you now need to run the go-pear.phar script to complete the PEAR package installation process. The installation will display some install locations and config settings. Choose 1 to change the installation base setting to /usr/local/pear and press Enter to complete the procedure.

001> sudo php  q go-pear.phar

PHP configuration

With the PEAR library downloaded and installed on your machine, we finally need to edit the php.ini configuration file to include a path reference to the PEAR libraries. Use the Terminal app to navigate to the .ini file and use a command line editor to include the following line to reference the library:

001 > sudo vi /etc/php.ini
002 include_path = “.:/usr/local/pear/share/pear”

Path Variable

Check your PHP Code with CodeSniffer
The PEAR package is now installed, but we have a long path name to reference when running pear commands in the Terminal. Edit your bash profile file, and add the ‘export PATH’ line to the bottom to add an environment variable to allow us to access PEAR without typing the complete directory location:

001 > sudo vi ~/.bash_profile
002 export PATH=/usr/local/pear/bin:$PATH

Install CodeSniffer

With PEAR installed, we can now download the CodeSniffer tool. Thankfully, PEAR makes this really easy for us. We simply need to type the following command into a Terminal window, and PEAR will download a copy of the application from its repository.

001 > sudo pear install PHP_CodeSniffer        

Helping hands

Check your PHP Code with CodeSniffer
We’ll be running the CodeSniffer tool from a command line, so how do we find out what commands we can pass to it? Open a Terminal window and navigate to the location of your PHP webroot. Once inside the directory simply type in the shortcode command for CodeSniffer and hit enter to bring up the available commands.

001 phpcs –help

First Test

Go ahead and extract the sample files from the resource disc and place them directly in your PHP webroot. Let’s run our first test on the entire directory, although we could specifically choose to test individual files if we wished. With Terminal open and in the webroot directory, call CodeSniffer to test the current directory.

001 > phpcs ./

Failure

Our sample file failed the default sniff tests for code layout, hinting and commenting standards. CodeSniffer will output a detailed level of information for each failure on a file-by-file basis, line-by-line, offering you the solution to remedy the errors and to ensure your code passes the tests.

001 FILE: /Websites/phptest/WebDesMag.php
002 ————————————————————-
004 FOUND 2 ERROR(S) AFFECTING 2 LINE(S)
005 ————————————————————- 
006  10 | ERROR | @author tag comment indented incorrectly;
expected 
007 3 spaces but
008 | | found 4
009 12 | ERROR | @link tag comment indented incorrectly; expected 5 spaces but
010 | | found 6
011 ————————————————————-

Extra detail

The initial response from CodeSniffer tells us what’s wrong, and on which line, in which document, which is great – and incredibly useful. We can, however, ask for more specific details through reporting options. We’ll use one of the report options to include the source codes. Run the check again with the optional –s parameter:

001 > phpcs –s ./
002 
003 FILE: /Websites/phptest/WebDesMag.php
004 ————————————————————-
005 FOUND 2 ERROR(S) AFFECTING 2 LINE(S)
006 ————————————————————–
007 10 | ERROR | @author tag comment indented incorrectly; expected 3 spaces but
008 | | found 4 (PEAR.Commenting.FileComment.TagIndent)
009 12 | ERROR | @link tag comment indented incorrectly; expected 5 spaces but
010 | | found 6 (PEAR.Commenting.FileComment.TagIndent)
011 ————————————————————-

Finding issues

In this instance the fix is quite simple. The particular sniff tests we ran are quite strict on the spacing of tag comments. Open up the file WebDesMag.php and take a look at the top of the document to find the @author and @link comments, which have one extra space compared to the others.

001 * @category PHP
002 * @package Web_Des_Mag
003 * @author Matt Gifford 
004 * @license Enter a valid license here
005 * @link http://dev.monkeh.local/WebDes_Sniffer
006 */ 

Fixing problems

Remove the two extra spaces in the file (one for each of the problematic tag comments). This should bring the comments in line with the rest in the same comment block. Run the test again and you should now see nothing returned in the console, which is a good sign.

Changing standards

CodeSniffer comes prepackaged with a number of coding standards that we can use to perform the tests. Each one is tailored with slightly different tests and requirements for code. By default, the PEAR standard will be used. We can see what standards are installed and select a new default for testing.

001 > phpcs -i
002 The installed coding standards are MySource, PEAR, PHPCS, Squiz and Zend
003 > phpcs –config-set default_standard PHPCS

Reporting format

When we ran our previous tests in the last few steps we received a fairly simplistic report from the sniff tests, which was run by default. What
we can do this time is set another configuration value to change the default reporting style we want to use. Let’s change it to return detail using the summary format, which will provide us with the source for each error in a separate table.

001 > phpcs –config-set report_format=summary

Watching progress

The CodeSniffer tool, as you have seen, will output the results of any errors or warnings at the end of its cycle through the code. We can change this to show us what’s happening and has been discovered as it runs through the code. To do so, simply change another configuration value via the command line.

001 > phpcs –config-set show_progress 1 

Custom standards

Check your PHP Code with CodeSniffer
As a tool to assist in coding guidelines, you can easily create your own coding standard to perform your own tests on your code. Each standard is a directory structure and an XML file containing test rule sets. Create the required directories for your custom standard within the CodeSniffer/Standards directory:

001 > cd /path/to/PHP_CodeSniffer/CodeSniffer/Standards
002 > mkdir MyStandard
003 > mkdir MyStandard/Sniffs 

Create RuleSet

Now we need to create our ruleset.xml file, which can be found residing in our custom standard directory. At its most basic, this file will
inform CodeSniffer that it contains sniff tests that can be run, but we can also extend it to select which tests from other standards we wish to run as part of our guidelines.

001 < ?xml version=”1.0”?>
002 
003 Our new custom coding standard.
004

Adding rules

Let’s add some of the existing standards in to our ruleset.xml definition file for use in our tests. We can pick entire standards including all underlying tests but excluding some specific sniffs, and in some cases we can overwrite default values to customise the testing boundaries.

001 <rule ref=”PEAR”/>
002 <rule ref=”Squiz”>
003 <exclude name=”Squiz.PHP.CommentedOutCode”/>
004 </rule>
005 <rule ref=”Generic.Files.LineLength”>
006 <properties>
007 <property name=”lineLimit” value=”90”/>
008 <property name=”absoluteLineLimit” value=”100”/>
009 </properties>
010 </rule>

New Sniff

As well as importing existing sniff tests from other standards, we can create our own for use in our custom standard definition. Each sniff is located in a sub-directory that relates to its category or function. Create a new file called DisallowHashCommentsSniff.php in MyStandards/Sniff/Commenting. We can create the file comment block in the document.
001 /**
002 * This sniff prohibits the use of Perl style hash comments.
003 *
004 * PHP version 5
005 *
006 * @category PHP
007 * @package PHP_CodeSniffer
008 * @author Matt Gifford 
009 * @license http://matrix.squiz.net/developer/tools/php_cs/ licence BSD Licence
010 * @version SVN: $Id: coding-standard-tutorial.xml,v 1.9 2008-10-09 15:16:47 cweiske Exp $
011 * @link http://pear.php.net/package/PHP_CodeSniffer
012 vax

Define class

Each sniff test needs to implement the PHP_CodeSniffer_Sniff interface to ensure that the correct libraries and packages are run when the tests are invoked. The class must also have a descriptive comment block above it for clear documentation and readability.

001 class MyStandard_Sniffs_Commenting_DisallowHashCommentsSniff implements PHP_CodeSniffer_Sniff
002 {
003 
004 } // end class

Register function

Next we need to add the register method within the class, which allows the sniff to define which of the token types it wants to process in the test. When CodeSniffer encounters any of these while running the next sniff test, it will process the file and determine where that token type was found and inform us.

001 public function register()
002 {
003 return array(T_COMMENT);
004 }//end register()

Process function

We’re nearly there, but we now need to add the process function. This takes a representation of the current file being checked and the position in the stack where all of the tokens were found. This will check for the existence of the disallowed comment and generate the required error output message and stack information.

001 public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
002 {
003 $tokens = $phpcsFile->getTokens();
004 if ($tokens[$stackPtr][‘content’]{0} === ‘#’) {
005 $error = ‘Hash comments are prohibited; found %s’;
006 $data = array(trim($tokens[$stackPtr] [‘content’]));
007 $phpcsFile->addError($error, $stackPtr, ‘Found’, $data);
008 }
009 }//end process() 

Test File

With our new sniff written in our custom standard, let’s create a simple PHP file to test the output of our sniff. This will contain a number of ‘illegal’ hash comments, which our sniff will be looking for. Create this file in the PHP webroot directory in which we are checking.

001 < ?php 002 003 # This is a standard PHP file 004 var $code_message = ‘Code should be readable.’; 005 # Output our string message 006 echo $code_message; 007  008 ?>

Run sniffs

With our test file in place, lets run CodeSniffer using our custom coding standard. We can either set it as the default standard or define it as an argument as part of the command line request. We’ll also set an optional parameter to obtain verbose output for more information.

001 > phpcs -s -v –standard=MyStandard ./ 

Check output

Check your PHP Code with CodeSniffer
The addition of the verbose parameter gives us a greater level of understanding as to what is happening when CodeSniffer performs the tests. We can see from the output via the command line how quickly the sniff tests were performed and how many tokens were found in each file.

001 Registering sniffs in MyStandard standard… DONE (1 sniffs registered)
002 Creating file list… DONE (2 files in queue)
003 Changing into directory /Websites/phptest
004 Processing testfile.php [24 tokens in 8 lines]… DONE in < 1 second (2 errors, 0 warnings)
005 Processing WebDesMag.php [107 tokens in 56 lines]… DONE in < 1 second (1 errors, 0 warnings)

Sniff success

Check your PHP Code with CodeSniffer
Our custom standard and sniff tests were processed against the files in the specified directory, and we can see from the results that the prohibited hash comments were found in our test file. We can now easily fix our code.

001 FILE: /Websites/phptest/testfile.php —————————————————–
002 FOUND 2 ERROR(S) AFFECTING 2 LINE(S)
003 ————————————————
004 3 | ERROR | Hash comments are prohibited; found # This is a standard PHP file
005 | | (MyStandard.Commenting. DisallowHashComments.Found)
006 5 | ERROR | Hash comments are prohibited; found # Output our string message
007 | | (MyStandard.Commenting. DisallowHashComments.Found)
008 ————————————————

CODE LIBRARY

Let’s take a closer look at some of the techniques used by default sniff tests in CodeSniffer

This particular sniff (below) is currently searching for a number of token types within each of the processed files.

001 public function process(PHP_CodeSniffer_ File $phpcsFile, $stackPtr)
002 {
003 $find = array(
004 T_COMMENT,
005 T_DOC_COMMENT,
006 T_CLASS,
007 T_FUNCTION, 
008 T_OPEN_TAG,
009 );

To assist in formatting of code and readability for consistency, this sniff checks for additional blank line requirements.

001 // Exactly one blank line before tags.
002 $params = $this->commentParser- >getTagOrders();
if (count($params) > 1) {
003 $newlineSpan = $comment->getNewlineAfter();
if ($newlineSpan !== 2) {
004 $error = ‘There must be exactly one blank line before the tags in function comment’;
005 if ($long !== ‘’) {
006 $newlineCount += (substr_count($long, 
007 $phpcsFile->eolChar) – $newlineSpan + 1);
008 
009 }
010 $phpcsFile->addError($error, 
011 ($commentStart + $newlineCount), 
012 ‘SpacingBeforeTags’);
013 
014 $short = rtrim($short, $phpcsFile- >eolChar.’ ‘);
015 }
016 }

CodeSniffer tests are thorough and can be very strict on the layout of code and the number of spaces between tokens.

001 if ($spaceBeforeVar !== 1 && $spaceBeforeVar !== 10000 && $spaceBeforeComment !== 10000) {
002 $error = ‘Expected 1 space after the longest type’;
003 $this->currentFile->addError($error, $longestType,
004 ‘SpacingAfterLongType’);
005 } 
006
007 if ($spaceBeforeComment !== 1 && $spaceBeforeComment !== 10000) { 
008 
009 $error = ‘Expected 1 space after the longest variable name’;
010 $this->currentFile->addError($error, $longestVar, 
011‘SpacingAfterLongName’);
012 
013 }

  • Tell a Friend
  • Follow our Twitter to find out about all the latest web development, news, reviews, previews, interviews, features and a whole more.
    • http://kk.mercubuana.ac.id/ ululf01

      nice share
      thank you

    • http://sprouter.com/jusicely causes of sore nipples

      Thanks for sharing your info. I truly appreciate your efforts and I am waiting for your next write ups thanks once
      again.