PHP Static Analysis in Sublime Text

Posted: 2013-08-20
Category: PHP

Coding Standards have been around for the longest time and recently they're starting to become more widespread in PHP. While learning Python I really enjoyed how Sublime Text 2 would shout at me for using too many empty lines, using tabs instead of spaces and even things like declaring unused local variables, importing modules that were never used, etc. This was pretty cool, and I was soon writing beautiful Python code without any concern over which way things should be done.

I've been doing this with PHP for the last year, but trying to get a new-hire going with this stuff was hard. We smashed through it taking notes so now I've written it up for you guys.

Step 1: Match PHP versions with your dev environment

If you locally develop using Vagrant or some other VM (and you really should be) you will most likely have a different local version of PHP to the one in the box.

For me, on OSX php -v displayed PHP 5.3.15 and vagrant is on 5.4.6. Using homebrew and the homebrew-php repo this was relatively easy.

You don't need to install all the extensions and everything to make it a fully operational environment, you just need to make sure that when php -l runs, Sublime Text 2 is using a version that understands the same syntax. For example, if you skip this step and your local version of php is 5.3, Sublime Text is going to shout errors at you every time you try to use a trait or short array syntax.

Step 2: Moar Static Analysis Tools

There are several tools we'll be using: PHP Mess Detector, PHP CodeSniffer and PHP Coding Standards Fixer.

Depending on how you have PEAR installed, you might need to prefix these commands with sudo.

$ pear channel-discover pear.phpmd.org
$ pear channel-discover pear.pdepend.org
$ pear install --alldeps phpmd/PHP_PMD
$ pear install PHP_CodeSniffer

Update 13/12/2013: The reason I originally suggested PEAR was down to homebrew doing some fairly odd shit when I tried installing these packages. It was trying to install a .phar but PHP was not allowed to create a phar itself, so I had to switch phar.readonly to Off in php.ini. It might be worth doing that - just to avoid PEAR - so once you've made the change run this:

$ brew tap josegonzalez/homebrew-php
$ brew install phpmd
$ brew install php-code-sniffer
$ brew install php-cs-fixer

Step 3: Install the Sublime PHP CS plugin

This is the plugin that brings it all together.

You'll need to go to "Preferences > Package Settings > PHP CodeSniffer > Settings - Default". Set these values:

// Show the errors in the quick panel so you can then goto line
"phpcs_show_quick_panel": false,

Switching that to false will avoid the obnoxious pop-up that lists all errors in your face. Sometimes you want to ignore a few errors, this won't let you.

// It seems python/sublime cannot always find the phpcs application
// If empty, then use PATH version of phpcs, else use the set value
"phpcs_executable_path": "/usr/bin/phpcs",

Set the full path to phpcs. You can use which phpcs for this.

"phpcs_additional_args": {
    "--standard": "psr2",
    "-n": ""
},

Because you know you love spaces over tabs.

// Path to where you have the php-cs-fixer installed
"php_cs_fixer_executable_path": "/usr/local/bin/php-cs-fixer",

Find the fixer.

// Are we going to run php -l over the file?
"phpcs_linter_run": true,

Here is the linting we were taking about.

// Execute phpmd
"phpmd_run": true,

Will shout at you for producing stupidly complex functions and methods. If it says a method is complicated, try splitting it in half.

// It seems python/sublime cannot always find the phpmd application
// If empty, then use PATH version of phpmd, else use the set value
"phpmd_executable_path": "/usr/bin/phpmd",

Tell Sublime where phpmd is.

Play around with the other settings if you like, but do that in "Settings - User" so you still have this default to fall back on. This default is the least invasive and most useful setup I have so far, but can certainly be tweaked.

Other IDEs

If you want to do this with something other than Sublime Text then there are plenty of other options.

Only one IDE I've spotted so far has CodeSniffer support out of the box:

Some require extensions but have some simple tutorials:

Wether you think coding standards are important or not, at some point in your career you are almost certainly going to be forced to use one. Some Lead Developers like me will use CodeSniffer to detect invalid formatting on the Continuous Integration server (Jenkins, Travis-CI, Bamboo, etc). Depending on how the thresholds for checkstyle warnings are configured, a developer placing too many brackets and new lines in the wrong place could mark the build as unstable, or even fail it.

This might all sound petty, but some rules have extremely valid reasons. You put a new line at the end of the file? That could let whitespace sneak into the output, which will cause bugs in production. I figure it is better for your IDE/editor to shouts at you, rather than the whole dev team.

Comments

Gravatar
Matt Cairns

2013-08-20

There seems to be a typo in the pear tools installation.

These lines:
$ pear install --alldeps phpmd/PHPPMD
$ pear install PHPCodeSniffer

Should look like this:
$ pear install --alldeps phpmd/PHP_PMD
$ pear install PHP_CodeSniffer

Thanks for the tutorial, trying it out now!

Gravatar
Edgard

2013-08-20

Thanks for the post! There are sometime that I want to use o Codesniffer, but I did not find a reason. Now I understood how to works and the benefits.

PS: Sorry my English :D

Gravatar
Pete

2013-08-20

Coincidentally I have recently got the above set up on my machine two - with a couple of differences:

I have installed php5.4 and php5.5 via homebrew-php (https://github.com/josegonzalez/homebrew-php)

I couldn't get PEAR to work but fortunately homebrew-php provides formula for PHP Mess Detector, PHP CodeSniffer and PHP Coding Standards Fixer.

So it was easy as:

$ brew install php-code-sniffer && brew install php-md

no PEAR or sudo involved :)

Gravatar
Anahkiasen

2013-08-20

Please, not PEAR. :D
Composer can install global dependencies now, you can replace the whole first block with :

composer global require squizlabs/php_codesniffer:dev-master

Gravatar
Simon

2013-08-21

My IDE always puts a blank line at the end of any document unless its a php document with a tailing ?> in which case it will shout at me saying that its not required and will cause white space issues :) I can not remember why, but is there not a reason why some IDE's add a new line to the end of files?

Gravatar

2013-08-21

@Matt: Thanks, fixed.

@Pete: Nice. I set up CS Fixer with homebrew but it wasn't much fun. I had to enable phar.read_only to false in the homebrew php.ini, but when I ran homebrew it was for some reason still looking at the OSX php.ini, so I had to change both, even though my paths were definitely set up right. The whole thing left a bad taste in my mouth so I just avoided it.

As much as folks bash PEAR, it did it's job perfectly in this instance.

@Anahkiasen: Same as above. Composer will install these (and I do so on Jenkins and Vagrant), but installing them globally is a little hacky and I couldn't be bothered forcing that on people. Again, PEAR did it's job just fine.

@Simon: No idea buddy!

Gravatar
Alex Bilbie

2013-08-22

I prefer these OSX PHP packages http://osx.liip.ch over Homebrew

Gravatar
Dan

2013-08-23

Hi Phil,

Any ideas how to disable certain rules? In particular "Avoid using unused local variables" since I'm using compact() to pass them to my views. The "Opening parenthesis of multi-line function call must be the last content on the line" one annoys me too!

I've read you can create a custom ruleset with PSR2 as the reference, but can't for the life of me find where this rule is actually defined.

Thanks for the write-up!

Gravatar

2013-08-24

@Dan: Yeah those rules can be annoying. You can set custom files for yourself in config, each system has their own XML syntax or CLI args for excluding certain rules.

https://gist.github.com/philsturgeon/6320152

You might find this interesting. It's my documentation of discrepencies between the intention of PSR-2 and the implementation of the CodeSniffer rule-set. The "Opening parenthesis of multi-line function call must be the last content on the line" error you mention is nothing to do with PSR-2 and will hopefully be ripped out once a few other things have been taken care of.

Gravatar
Amit

2013-08-27

Hey Phil,

Thanks for the wonderful article.

Any idea if php-cs-fixer will fix up the code like http://paste.laravel.com/M6n for PSR2 coding standards ?

I can see the Sniffer showing me all the issues for indentation etc but for some reason fixer isn't fixing them all.

Isn't fixer supposed to do that ?

- Thanks again !

Posting comments after three months has been disabled.