Coding Standard

Introduction

This document is an attempt to consolidate the coding standards of my ever growing list of software projects. It is mostly specific to PHP, HTML, CSS, and SQL.

While I would like to have this standard written in stone, forever unchanging and always correct, that’s obviously impossible. ūüôā So consider this a living document that can change at anytime. Changes to this standard will be communicated as best as they can to all active and/or registered developers.

Send any questions, suggestions, or comments to russ.collier@gmail.com.

Objective

The purpose of this standard is to keep the source code for my projects clean, consistent, readable, and hopefully more maintainable. Please follow this standard or watch your code get handed back to you for clean-up and reformatting!

Editor Settings

Tabs vs. Spaces

Spaces (a.k.a soft-tabs) only! This makes the source code look consistent in any editor (with a fixed width font). CSS and XML/HTML should be 2 spaces per tab, everything else should be 4 spaces per tab.

Linefeeds

While I am not quite as strict about this, I strongly encourage using Unix style line feeds (LF, ASCII 10, “\n”, etc.) for all files.

General Whitespace

There should not be any whitespace at the end of a line. Similarly, lines that consist of nothing but a linefeed character should not have any spaces either, meaning if a line is blank, it should be just that… blank!

Recommended Editors

Personally I prefer phpStorm these days for PHP development.

For quick and dirty edits, I am a big fan of¬†TextPad¬†for Windows. For me on UNIX, it’s¬†Vim¬†(or just basic vi) or nothing! ūüôā

Naming Conventions

Naming Style

Use camelCase for all variable and function names, but NOT Hungarian notation. Example: good: $memberName bad: $strMemberName or $sMemberName.

The first letter of each “word” should be upper case, except for the first word. The exception to this are class names, where the first letter of every word should be uppercase. Example:SqlMapper

In the case of acronyms, the first letter should be uppercase, with the rest lowercase. Example: $url, SqlMapper, XmlRpcConnector.

Interfaces

The exception to all of these is when naming an interface. An interface name should always be prefixed with an upper case I, followed by the typical class standard naming. Example:IProvideThreadReplies.

Also, whenever possible, try to name the interface so it reads like a sentence describing what it provides or does for you. IProvideSessionData, ISaveThingsToDatabase, etc.

Property/Variable Names

Use camelCase as mentioned above. Make variable names short, but descriptive, nouns. Example: good: $memberName, bad: $a, $currentMemberNameInThisFunction. Try to use your best judgement.

Property names should only start with a letter, a through z. Do not prefix any property names with an underscore, even if they are private. Class member visibility keywords are good enough to indicate a member is private or protected. (I only follow this last bit about the underscore for PHP. For C# I use the _ prefix).

Loop/Iterator Variables

In general, the only time when you can use a one-character variable name is for simple numeric variables used for iteration, unless there’s another variable already in use with a more useful name. Start outer loops with¬†$i, then just go down the alphabet ($j,¬†$k,¬†$l, etc).

Constants and Globals

For constants (global or class level) and global variables in general, the variable should be named in all uppercase letters, with underscores separating “words” in the variable name. Examples:CACHE_DIRECTORY,¬†$DEFAULT_DATABASE_HOST, etc.

Method/Function Names

These follow the same basic conventions as variable names, but method names should generally include a verb. Example: getMemberName(), calculatePayment().

Method/function names should only start with a letter, a through z. Do not prefix any method/function names with an underscore, even if they are private. Class member visibility keywords are good enough to indicate that a member is private or protected.

Method/Function Arguments

These follow the exact same convention as variable names. One should be able to tell how to use a method or function just by looking at the declaration/method signature.

Example URLs

All example, sample, and/or default URLs should be “example.com”. See¬†RFC 2606¬†for more information.

Class Namespacing

Since the PHP language as of version 5.2.0, does not provide any formal way of separating classes into different namespaces or packages, this will be enforced by a class naming convention. All classes should begin their class name and declaration with <Project_Name>_, for example:¬†class¬†BuBOL_Forum. The name of the project at the beginning of the package is the only exception to the CamelCase rule, meaning it is acceptable to use “BuBOL” in the name, instead of “Bubol”.

Class Filenames

The file naming and directory structure standard is pretty much like PEAR and is probably best explained with an example.

If I have a class named: Zorm_DataSource_IDataSource, the file would be named: IDataSource.php and would be in the directory tree: Zorm/DataSource. Notice the directory structure matches the package namespace for the class, and the filename matches the actual class/interface name within our namespace work-around.

All class files must also end in .php.

Documentation Filenames

All plain text documentation files should have the filename extension “.txt” to make viewing them on Windows easier. Also, the filenames for such files should be all uppercase (e.g. README.txt instead of readme.txt) while the extension itself is all lowercase (i.e. txt instead of TXT).

Comments

Overview

All comments for classes and interfaces basically follow the standard Javadoc rules used for Java comments. A good reference to take a look at is: http://java.sun.com/j2se/javadoc/writingdoccomments/

General

Aside from standard file, class, property, and method comment blocks, you should only need to put comments around areas of code that are particularly ugly, or particularly clever. You don’t need to comment every line of code, but try to use your best judgement. Ideally the names of properties/variables and methods/functions should make the code self-documenting. Just remember: it is better to comment sooner rather then later, after you’ve forgotten where something is or what it does.

I prefer to be fairly specific about the expected data types for properties, parameters, return values, etc. (despite the fact that PHP is a dynamic, loosely typed language :-P). In the comment templates below, when you see DataType, it means to specify the data type of the value: String, Integer, Float, SomeClassName, Object, Mixed, etc. When an array is expected, put the data type name followed by square brackets: []. Example: String[] would indicate an array of strings.

Types of Commenting

For general comments in code (not file, class/interface, method, or property blocks) the following rules should be followed:

  • The Perl style commenting,¬†#, is¬†strongly¬†discouraged.
  • Use C style commenting,¬†/* */, for multi-line comments.
  • Use C++ style commenting,¬†//, for single line comments.
  • Only use Javadoc style commenting,¬†/** */¬†for file, class/interface, method, and property blocks.

Code Layout and Formatting

Number of Columns

The 80 column limit is not a huge deal these days in my opinion, but do not abuse the line length in your source code. Personally I feel 120 is a very lenient maximum length. The 80 column limit will not be strictly enforced, but try to use it as a guideline. If you have a line of over 120 characters long, maybe you should think about what you are trying to do and see if there’s a more readable (shorter) way to code that line. Cleverness in coding is appreciated, but readability and maintainability are higher priorities.

Liberal Use of Whitespace

Whenever possible, try to line up statements with whitespace. No spaces immediately after an open parentheses nor immediately before a closing parentheses For example:

if ('russ' == strtolower($firstName) &&
    'nobody' == strtolower($groupName) &&
    300 < $usageCount)
{
    $member = proceedWithLogin();
}
 
$lastName   = $member->getLastName();
$memberId   = $member->getId();
$loginCount = $member->getLoginCount();
$pageId     = $_GET['page_id'];
$newValues  = array('color'     => 'green',
                    'maxWeight' => 2000,
                    'callback'  => 'getValue',
                   );

Note the comma at the end of the last array element – this is not a typo! It helps prevent parsing errors if another element is placed at the end of the list later.

Include Braces

Always include the braces in any kind of control block. They help with code readability and avoid some simple logic errors.

Example:

// Bad
if ($someCondition) doThis();
 
// Bad
if ($anotherCondition) doThat();
 
// Good
if ($yetAnotherCondition)
{
    doThisLastThing();
}
else
{
    doNotDoAnything();
}

Where to Put Braces

Use BSD/Allman style: Make sure the open brace is on it’s own line. And make sure the closing brace is in the same column as the corresponding opening brace, again on its own line. Make sure no blank new line separates the brace and whatever is above or below the brace.

Example (also shows proper layout for a switch statement):

 

$someCondition = checkCondition();
if ($someCondition)
{
    while ($result->next())
    {
        if ($result->isBrokenWidget())
        {
            break;
        }
 
        switch ($result->getValue())
        {
            case 'A':
                doAStuff();
                break;
            case 'B':
                doBStuff();
                break;
            default:
                doDefault();
        }
 
        $result->move();
    }
}
else if ($someCondition && $someOtherCondition)
{
    doSomethingElse();
}
else
{
    die('Uh-oh!');
}
 
cleanUp();

Of course you should also rethink an area of code that contains a high amount of nested blocks of code ūüôā To avoid losing track of control statements in long blocks like this, try to avoid long blocks altogether!

Rather than checking for some condition, then doing a multi-line set of operations, check for the opposite condition and bail out early. This will help reduce nesting. For example:

// bad
function doStuff()
{
    if ($someCondition)
    {
        callThisThing();
        thenDoThisOtherStuff();
        sleepForABit();
        maybeDoOneMoreThing();
    }
}
 
// good
function doStuff()
{
    if (!$someCondition)
    {
        return;
    }
 
    callThisThing();
    thenDoThisOtherStuff();
    sleepForABit();
    maybeDoOneMoreThing();
}

Switch Statements

As shown above, the proper formatting for a switch statement is:

switch ($result->getValue())
{
    case 'A':
        doAStuff();
        break;
    case 'B':
        doBStuff();
        break;
    default:
        doDefault();
}

Conditional Statements

Never use the if/endif; structure. Always just use a typical C-style if statement with braces as shown above.

Use the ternary operator sparingly. When you do use it, make sure it is for a short, simple case.

Empty Methods

While empty methods are usually redundant or the smell of a bad design, when they are necessary they should be formatted like the following:

public function __construct()
{
}

Spaces Between Tokens

This helps with code readability. Put spaces between variables and operators, after commas. No spaces between element indices and square brackets in arrays, and after an opening bracket (parenthesis) or before a closing bracket (paranthesis). No spaces before a comma or semicolon though (except in a for loop declaration). Unless it’s a function call, there should be a space between the keyword/statement and the opening bracket.

Examples:

 

$min = 1;
 
$max = $min * 500;
 
$foo = 'value';
 
$bar = someFunction($foo, null); 
 
$baz = '';
 
for ($i = $min; $i <= $max; $i++)
{
    $baz .= $bar[$i];
}
 
print $baz . "\n";

Operator Precendence

When dealing with a less than trivial series of mathematical operation, always be explicit about the order of operations by using parentheses to force the precedence of an operation so you can know the exact order of operations by looking at it.

Bad:

$x + $y - $z / $w * $v

Good:

$x + (($y - $z) / ($w * $v))

Also, when checking a Boolean NOT, leave out the parantheses. Example:

 

if (!$member->isRegistered())
{
    promptForLogin();
}

SQL Statements

The three basic guidelines are: break lines on keywords, capitalize keywords, and use table aliases. The following is an example of proper formatting:

SELECT m.member_name, m.member_id
FROM members m
WHERE m.member_id IN (
  SELECT am.member_id FROM active_members am
);

Columns in SQL Statements

Be sure to always enumerate the names of columns in SQL¬†SELECT¬†and¬†INSERT¬†statements. Avoid using “SELECT¬†*”.

Comparisons Against Constant Values

This is more of a suggestion than an actual rule. When comparing a variable against some constant value, keep the constant value on the left hand side and the variable on the right hand side. This can prevent some simple, yet maddeningly difficult to debug logic errors. Example:

if (null == $memberObject)
{
    promptForLogin();
}
 
if (0 < count($mappingList))
{
    initialize();
}

One Class Per File

PHP classes should be in there own file, with only 1 class per file with the file named after the class it contains (see the naming conventions section above). No other code should be present in the file other than the class/interface contained within the file. However, it is allowable for other small snippets of code to be present in a class file for doing things like checking if the file should be included.

The exception is when you have an interface in the file. Name the file after the interface and if there is one default implementation of the interface, you can put that implementation class in the same file as the interface, below the interface declaration/definition.

Also, the last line in a class file should be the closing PHP tag: ?>. Do not put a newline after this closing tag, it should be the very last characters in the file.

Member Visibility

For class members, always explicitly put the visibility (public, protected, or private) before the member declaration/signature.

Also, never precede private members with an underscore “_”. Let the language’s own visibility statement speak for itself.

PHP Specifics

PHP Predefined Globals

Always use the superglobals: $_SERVER, $_POST, $_GET, $_COOKIE, $_SESSION, etc. as opposed to their deprecated $HTTP_ equivalents.

PHP Tags

To ensure some degree of backwards compatibility, XML support, and consistency, all PHP script tags should be in the form of <?php … ?> (“long” open tags), and preferably the tags should be on their own lines with 1 empty newline immediately after the opening tag¬†<?php¬†and 1 empty newline immediately before the closing tag¬†?>¬†unless it’s a concise 1 liner in the midst of HTML (e.g.¬†<?php¬†print¬†$currentTime; ?>)

Other PHP Settings

register_globals

ALWAYS write code assuming the register_globals setting is unknown. To do this, simply use the superglobals like $_POST, $_GET, etc to access incoming data, and initialize all variables before using them.

magic_quotes_gpc

ALWAYS write code assuming the magic_quotes_gpc setting is unknown. Check the status of this setting with get_magic_quotes_gpc() and use addslashes() accordingly.

Quoting Strings

If you have escape sequences (e.g. \n, \”) in your string, use double quotes around it. If not, use single quotes around the string. This saves unnecessary interpolation parsing.

Also, in general, concatenate variables in strings, rather than embedding them (interpolation). This helps the variables in strings stand out more in most editors.

Associative Array Keys

When accessing a value in an associative array, use single quotes around the array key to increase readability.

Bad: $bluh = $my_array[narf];
Good: $bluh = $my_array['narf'];

Always concatenate array values in strings, never embed an array element in a string, expecting it to be interpolated.

Bad:

$foo = "Here is a string with an array element: $someArray[bar]\n";

Good:

$foo = 'Here is a string with an array element: ' . $someArray['bar'] . "\n";

Besides, I think the first line of the example with throw a syntax error anyway (at least in PHP 4.x). By concatenating values into strings the variable tends to stand out more in most editors.

Magic Numbers

When in doubt, make numbers into declared constants. Generally, the only time it is acceptable to use a literal number instead of a constant is when checking if an array has 0 elements. Preferably group constants into the appropriate class/interface.

Class Constants

Constants should be grouped together in the appropriate class or interface using the const keyword to declare constants.

Increment/decrement Operators

Generally, the only time increment or decrement operators should be on their own line is in a loop statement. Otherwise, always put them on their own line to help keep code readable/easily understoond. Example:

Bad: $array[$i++] = $bluh;

Good:

$i++;
$array[$i] = $bluh;

Initialize All Variables

If you are not sure about the state of a variable, especially before critical/sensitive sections of application logic, use the built-in isset() function to test if the variable has been initialized yet. If you are writing a method or function and can make valid assumptions, try to use default parameters to provide known values for uninitialized/unused parameters.

Booleans and Nulls

For all boolean values use the keywords true and false instead of 0 and not 0. As usual this helps keep the code concise and readable. Also, use the keyword null for uninitialized objects. All of these keywords should be lowercase, always.

Built-in Functions

Whenever you call a built-in PHP function and/or statement, always make sure it is in lowercase, even if PHP allows otherwise. The exception to this is when the PHP documentation specificies a function/method definition as something other than all lowercase, like DOMDocument->createElement().

Develop with E_ALL

Development work should be done with the error reporting level set to E_ALL. There should never be any warnings or notices when the code runs. If there are warnings or notices, it could indicate some variables are not being properly sanitized.

Static Members

Whenever accessing static class members or even class constants within the declaring class itself, always use the self or parent keywords to reference the member, not the class name itself.

Flow control

Avoid excessive amounts of nested if statements in loops by making use of the break and continue keywords to control the flow of looping constructs.

Leave a Reply

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