At Zimco, we've started working on standardizing our coding but we ran into a little problem while we tried to automate the process of making sure our code adhered to that standard.

Why You Should Be Coding to a Standard

If you ever worked on a code base with multiple coders, I'm sure you've run into crazy mixed use of spaces and return lines:

if ( $test == $somethingElse ) {
    echo 'Foo';
}elseif($test=='true'){echo 'Bar!';}

This (extreme) case comes from different people doing what they think is the "best" but nobody agreeing on what that is. I think we get into our own way of doing things and everything else is wrong. This code makes me feel irrationally angry (so angry I'm having a hard time not fixing it...).

Ultimately, the best way to fix these kinds of formatting problems is to sit down and discuss what's best and have everyone stick to the same set of standards.

PSR

You might say:

There are hundreds of possible things you could discuss. How could we possibly decide on things the programming community has been fighting over for years like tabs vs spaces, open brackets on the same or new lines, and what line endings to use. Think of all the wasted man hours!!!!

The good news is that someone has already debated these issues and created a standard. The PHP Framework Interop Group (PHP-FIG) created two standards on coding. The first is PSR-1 and the second is PSR-2. These two standards create a set of rules for how you should write your code and several large PHP projects use these (see their home page).

It's very detailed and it gives you answers to life's big questions including:

  • tabs vs spaces (spaces)
  • open brackets on the same or new lines (depends on the context)
  • line endings (Unix)

And it also gets into nitty gritty details like spaces in if blocks. For example, the first if block is "wrong" and the second if block is right:

// no! 
if($this->isTrue()){

}

// yes!
if ($this->isTrue()) {

}

This one has taken some getting used to but I do think it's more readable.

PHPCS

One of the hard parts to getting on a standard is that it's hard to stick to the standard because there is so much to unlearn. PHP_CodeSniffer is a command line tool that allows you to check (and fix) your code to match the standard. It's easy to install (with composer) and it works really really well.

We can run phpcs on an entire directory but we can also run it on a single file:

$ vendor/bin/phpcs --standard=PSR2 Error.php 

FILE: ...ts/FutureBlogPosts/Creating Your Own Standard in PHPCS/Error.php
----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
----------------------------------------------------------------------
 5 | ERROR | [x] Opening brace of a class must be on the line after
   |       |     the definition
----------------------------------------------------------------------
PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------

In this example our Error.php file contains a class that's defined like this:

class Error {

PSR-2 says it should should look like this:

class Error 
{

phpcs comes with another tool that can automatically fix some errors in your files called phpcbf:

$ vendor/bin/phpcbf --standard=PSR2 Error.php 

So that's super simple. Guess we can call it a day...

PSR2ZF1

What about the case where you don't agree with all of the recommendations (you should get behind them if you don't) or you're trying to run PHPCS against a code base that's using a framework that doesn't work with PSR2?

The simple answer is that you'll need to create your own standard.

Several of my active projects are still using Zend Framework 1 (and it's not a priority to change them) and running phpcs on most classes in these projects result in the following errors:

$ vendor/bin/phpcs --standard=PSR2 ZendFramework1.php 

FILE: ...BlogPosts/Creating Your Own Standard in PHPCS/ZendFramework1.php
----------------------------------------------------------------------
FOUND 2 ERRORS AFFECTING 1 LINE
----------------------------------------------------------------------
 3 | ERROR | Each class must be in a namespace of at least one level
   |       | (a top-level vendor name)
 3 | ERROR | Class name "Application_Model_User" is not in camel caps
   |       | format
----------------------------------------------------------------------

Time: 22ms; Memory: 3.25Mb

Creating and Testing Your Own Standard

In order to create our own standard we're going to create a file named PSR2ZF1 and put it in the root of our project:

<?xml version="1.0"?>
<ruleset name="PSR2ZF1">
    <description>The PSR2ZF1 coding standard.</description>
    <arg name="tab-width" value="4"/>
    <rule ref="PSR2" />
</ruleset>

This basically setups the standard to use PSR as the base.

The next thing we need to do is remove the sniffs that we don't need. To do this we're going to run phpcs with the -s switch:

$ vendor/bin/phpcs --standard=PSR2ZF1.xml -s ZendFramework1.php
FILE: ...BlogPosts/Creating Your Own Standard in PHPCS/ZendFramework1.php
----------------------------------------------------------------------
FOUND 2 ERRORS AFFECTING 1 LINE
----------------------------------------------------------------------
 3 | ERROR | Each class must be in a namespace of at least one level (a
   |       | top-level vendor name)
   |       | (PSR1.Classes.ClassDeclaration.MissingNamespace)
 3 | ERROR | Class name "Application_Model_User" is not in camel caps
   |       | format (Squiz.Classes.ValidClassName.NotCamelCaps)
----------------------------------------------------------------------

The text in () indicated the sniffs that are failing so we can just exclude them from the standard using the exclude option:

<?xml version="1.0"?>
<ruleset name="PSR2ZF1">
    <description>The PSR2ZF1 coding standard.</description>
    <arg name="tab-width" value="4"/>
    <rule ref="PSR2">
        <exclude name="PSR1.Classes.ClassDeclaration.MissingNamespace"/>
        <exclude name="Squiz.Classes.ValidClassName.NotCamelCaps"/>
    </rule>
</ruleset>

$ vendor/bin/phpcs --standard=PSR2ZF1.xml -s ZendFramework1.php
$

.editorconfig

In order to help you keep your code in standard you can use an editorconfig file and the Sublime Text EditorConfig plugin. The file below gets you the basics that you'll need (that are supported by EditorConfig).

# editorconfig.org
root = true

[*.php]
indent_style = space
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

You can also automatically run phpcs when you save a file in Sublime Text but I'll cover that in a future post.