PHP Coding Guidelines

The following PHP coding guidelines represent my own conventions and standards which I code by, along with some CakePHP conventions when developing with CakePHP, my PHP MVC framework of choice.

These PHP coding guidelines are by no means an industry standard, nor are they intended to tell you PHP coders out there how things should be done. I simply want to share the PHP coding guidelines which I follow and enforce when working with other developers on larger projects.

Laying down some coding guidelines like these helps to provide a more structured and rapid development environment, and makes the PHP code more predictable and easier to debug.

PHP Code Delimitation

PHP code must always be delimited by the full-form, standard PHP tags:

<?php
 
?>

Short tags are never allowed:

<?
 
?>

The PHP echo() shortcut syntax is also not allowed:

// Do not use:
<?=$sVarName?>
 
// Instead use:
<?php print $sVarName; ?>

Always use four spaces for code indentation. Do not use actual tabs. This prevents spacing issues when opening documents in different types of editors and when viewing source code in browsers. Most editors (e.g. Eclipse, Dreamweaver) allow you to set the tab key to insert a defined number of spaces instead of an actual tab. Setting this preference in your editor is strongly encouraged so as to speed up development and to prevent tabs from accidentally being inserted.

function foo() {
    $sVar = 'This is a function.'; // 4 spaces (1 tab)
    if (bar($sVar)) { // 4 spaces (1 tab)
        return $sVar; // 8 spaces (2 tabs)
    } else { // 4 spaces (1 tab)
        return false; // 8 spaces (2 tabs)
    } // 4 spaces (1 tab)
}

Note: To configure this in Eclipse PDT, go to Window -> Preferences -> PHP -> Formatter and set “Tab Policy” to “Spaces” and “Indentation size” to “4”.

String literals

When a string is literal (contains no variable substitutions), the apostrophe or single quote must always be used to demarcate the string, unless that string itself contains apostrophes. PHP will parse all double-quoted strings for occurences of variable substitution, thus taking more time to process. For enterprise-level applications with the possibility of hundreds of concurrent users, this can amount to a significant reduction in performance.

Standard string literals

$sVar = 'A string';

This rule goes for strings within function calls and constructs as well:

fooBar('string1', 'string2');
print 'This is a string';

Note: Using double quotes for string demarcation throughout programs can increase processing time significantly, thus they are not permitted unless the string itself contains apostrophes.

String literals containing apostrophes

When a literal string itself contains apostrophes, it is permitted and preferred to demarcate the string with quotation marks or “double quotes.” This is especially encouraged for SQL statements:

$sql = "SELECT id, name FROM people WHERE name = 'Fred' OR name = 'Susan'";

Note: The above syntax is preferred over escaping apostrophes so as to improve readability. Double quotes are only permitted when the string itself contains apostrophes.

Variable substitution

All variable substitution must be done with concatenation and should never occur within double quotes, due to a loss in both performance and readability. Substituting variables within double quotes can increase processing time by a factor of three. See this article showing some speed tests that were performed. The PHP manual itself also states, in regard to variable substitution within double quotes, “If a dollar sign ($) is encountered, the parser will greedily take as many tokens as possible to form a valid variable name.”

// Incorrect syntax:
print "Hello, my name is $sName.";
$sql = "INSERT INTO companies (name, phone, fax) VALUES ('$sName', '$sPhone', '$sFax')";
 
// Correct syntax:
print 'Hello, my name is ' . $sName;
$sql = "INSERT INTO companies (name, phone, fax) VALUES ('" . $sName . "', '" . $sPhone . "', '" . $sFax . "')";

String concatenation

Strings are concatenated using the “.” (period) concatenation operator. A space must always be added before and after the “.” operator to improve readability.

Inline concatenation

$str = 'Concatenate this string with ' . $sVar1 . ' and ' . $sVar2 . '.';

Multiple line concatenation

When concatenating strings with the “.” operator, it is permitted to break the statement into multiple lines to improve readability. In these cases, each successive line should be indented with at least four spaces (1 tab), and the same number of spaces must be used for each indented line such that the “.” operators are aligned on the left side.

$sql = 'SELECT id, name FROM people '
       . "WHERE name = 'Susan' "
       . 'ORDER BY name ASC';

You may also concatenate a string by redefining it with the concatenation operator (when necessary):

$sql = 'SELECT id, name FROM people ';
$sql .= "WHERE name = 'Susan' ";
$sql .= 'ORDER BY name ASC';

Concatenation when printing to the screen

When printing a string to ouput which includes concatenation, the print() construct must be used.

print 'Concatenate this string with ' . $var1 . ' and ' . $var2 . '.';

An alternative to concatenating ouput is using the echo() construct with multiple parameters, separated by commas:

echo 'Concatenate this string with ', $var1, ' and ', $var2, '.';

Although the concatenation operator ( . ) may be used with the echo() construct, the above syntax should be used instead for optimal performance. Using the concatenation operator with the echo() construct stores each concatenated section of the string as a separate object in memory before printing to the screen. Therefore, concatenating with the echo() construct is not permitted.

print() vs. echo()

You can find much discussion regarding this on the web. echo() is shown to have a marginal but insignificant advantage in speed over print() when used in simple, non-concatenated instances. This difference is not enough to be a concern, however.

For sake of consistency, it is preferred that developers use print() in all cases. The print() construct also provides a few advantages over echo() which are favorable from a programming point of view:

  • Although it is a construct and not a function, print() will return a value of 1 (true), whereas echo() has no return value.
  • Concatenating strings with the print() construct does not require additional stores to memory before executing.
// Because echo() does not behave like a function, the following code is invalid.
return echo 'true';
 
// However, the following example will work:
return print 'true';

Derived from: http://us3.php.net/manual/en/function.echo.php

Class declaration

Classes must be named by following the CakePHP naming conventions, and must use CamelCase notation. There should always be a single space between the class name and the opening bracket, and the opening bracket must be on the same line as the class name. The closing bracket must be on its own line at the end of the class declaration.

class MyFlippinSweetClass {
}

Class member variables

  • Member variables must be named by following the variable naming conventions.
  • Any variables declared in a class must be listed at the top of the class, prior to declaring any functions.
  • PHP 5+ only: The var construct is not permitted. Always declare the visibility of member variables by using one of the private, protected, or public constructs. Accessing member variables directly by making them public is permitted but discouraged in favor of accessor methods (typically prefixed with “set” or “get”).
  • All protected member variable names should begin with a single underscore (“_”), and all private member variable names should begin with two underscores (“__”). This is the only acceptable usage of underscores in a variable names. Member variables declared “public” may never start with an underscore.

Class member functions

If using PHP 5+, we have the advantage of using the public, protected, and private constructs for declaring functions. For sake of convention and compliance with CakePHP, however; all protected member function names should begin with a single underscore (“_”), and all private member function names should begin with two underscores (“__”). This is the only acceptable usage of an underscore in a function name. Public member functions may never start with an underscore.

Additionally, The return value must not be enclosed in parentheses. This can hinder readability and can also break code if a method is later changed to return by reference.

class MyClass {
 
    public $sVar1 = 'A public string var';
    protected $_aVar2 = array('A', 'protected', 'array', 'var');
    private $__bVar3 = false;
 
    public function foo() {
        return $this->sVar1;
    }
 
    protected function _bar() {
        return $this->_aVar2;
    }
 
    private function __fooBar() {
        return $this->__bVar3;
    }
}

Class instantiation

Always instantiate a class by using a variable of the same name:

$MyClass = new MyClass;

Note: Only variables representing objects may begin with a capital letter (as do class names). This helps to differentiate these declarations from other variable types.

Function declaration

Function names should be written using camelBack notation. There is no space between the function name and the opening parenthesis for the arguments. Like classes, there should always be a single space between the function name and the opening bracket, and the opening bracket must be on the same line as the function name. The closing bracket must be on its own line at the end of the function declaration.

function myFlippinSweetFunction() {
}

Additionally, functions should always be declared within a class, and should never stand alone. This provides a namespace for all functions and helps to identify their classification and location. For example, we would like to create a set of common functions that may be used throughout our application.

class Common {
    public function setGets($aGets) {
        foreach ($aGets as $mGet) {
            if (isset($_GET[$mGet])) {
                global $$mGet;
                $$mGet = $_GET[$mGet];
            }
        }
        return true;
    }
    public function arraySearch($mFind, $aArr, $aKeysFound = array()) {
        if (is_array($aArr)) {
            foreach ($aArr as $mKey => $mVal) {
                if (is_array($mVal)) {
                    $this->arraySearch($mFind, $mVal, $aKeysFound);
                } elseif (preg_match('/' . $mFind . '/', $mVal)) {
                    $aKeysFound[] = $mKey;
                }
            }
            return $aKeysFound;
        }
        return false;
    }
}

Now that we have defined our functions within the class Common, we can access them in our application using the scope resolution operator, thus providing the proper namespace.

Common::setGets(array('sSearchStr', 'sSearchScope'));
 
$aSearchRes = Common::arraySearch($sSearchStr, $$sSearchScope);

Variable declaration

Variable names should always begin with a lowercase key letter defining the data type, except for variables representing objects which begin with a capital letter. Object variables representing classes are the only variables that may begin with a capital letter, and they must match the class name. All variable names should be written in camelBack notation (or CamelCase for object variable names).

Key letters

The following key letters must be used to define variable data types:

  • i = integer;
  • f = float;
  • s = string;
  • b = boolean;
  • a = array;
  • r = resource id / reference;
  • m = mixed.

Note: “Mixed” refers to any variable that may change data types during a request, such as inside a foreach loop.

Examples

$iIntVar = 1;
$sStrVar = 'string';
$bBoolVar = true;
$aArrVar = array(
    'iKey1' => $iIntVar,
    'sKey2' => $sStrVar,
    'bKey3' => $bBoolVar
);
 
foreach ($aArrVar as $sKey => $mVal) {
    $aNewArr[$sKey] = $mVal;
}
 
$MyClass = new MyClass($aNewArr);
$sFile = 'file.xml';
$rHandle = fopen($sFile, 'r');

Variable names should also be descriptive, but as short as possible. Single character variable names are not permitted, except when used for incrementing / decrementing inside for and while loops. For example:

for ($i = 0; $i < 10; $i++) {
    doSomething($i);
}

NOTE: The rules for defining variable names apply to naming associative array keys as well. An exception to this rule for associative array keys is when you intend to use the key names for literal output to the user agent.

Control statements

All control statements must have a single space before the opening parenthesis of the conditional, and a single space after the closing parenthesis.

If / else / elseif statements

For “if” statements that include “elseif” or “else”, the formatting must be as in these examples:

if ($i != 2) {
    $i = 2;
} else {
    $i = 7;
}
 
if ($i != 2) {
    $i = 2;
} elseif ($bool === false) {
    $i = 4;
} else {
    $i = 7;
}

Switch statements

Each “case” within the “switch” statement must be indented 4 spaces (1 tab). Content under each “case” statement must be indented an additional 4 spaces. The “default” construct may never be omitted from a switch statement. The “break” for each case should always align with its respective “case” declaration.

switch ($iNumPeople) {
    case 1:
        print 1;
    break;
    case 2:
        print 2;
    break;
    default:
        print 0;
    break;
}

NOTE: It is sometimes useful to write a case statement which falls through to the next case by not including a break or return in that case. To distinguish these cases from bugs, any case statement where break or return are omitted must contain the comment “// break intentionally omitted”.

Ternary operator

The ternary operator (?:) is permitted only when assigning values to variables, printing output, or returning values. It may not be used in place of if / else statements which define program logic. To enhance readability, always place parentheses around the conditional statement.

// Proper use of the ternary operator
$bShowView = ($sAction == 'view') ? true : false;
print ($sAction == 'view') ? 'Viewing ' . $sViewType : 'Welcome';
return ($sAction == 'view') ? 'View' : 'Default';
 
// Improper use of the ternary operator
($sAction == 'edit') ? doAction('edit') : return false;

Including files

When including files that are used only once in a single request (e.g. classes, libraries, configuration), use only and always the require_once() function. This prevents the accidental inclusion of a file more than once. Only use the require() (not include()) function for files that may be used more than once in the same request.

<?php
require_once('config.php');
require_once('classes.php');
?>
 
<h2>Welcome to our website!</h2>
 
<?php
require('disclaimer.php');
?>

The above example illustrates requiring classes just once which then lend themselves to reuse by instantiating multiple objects, whereas the require() statement implies that the program output is consumable HTML.

require() vs. include()

The require() and require_once() functions are always preferred over the include() and include_once() functions. require() and require_once() will generate a fatal error and prevent the script from continuing to run if the specified file is not found, which in most cases would be a desirable outcome since the rest of the script will likely not run correctly without that file. include() and include_once() will only generate a warning if the file is missing and PHP will attempt to run the remainder of the script. require() and require_once() should be used in all cases so that it is always evident when an included file is missing (ideally during development), even if warnings are suppressed.

Constants

Constants should be defined in capital letters with words separated by an underscore “_”. Each constant should begin with an appropriate namespace to help derive its meaning:

define('COMPANY_NAME', 'ABC, Inc.');
define('COMPANY_ABBR', 'ABC');
define('PHONE_MAIN', '800-555-5555');
define('PHONE_FAX', '800-555-4444');

While you should try and keep constant names short, always ensure that the names are unique enough to prevent collisions with other constants defined in any third party plugins.

Documentation formatting / comments

All documentation blocks (“docblocks”) must be compatible with the phpDocumentor format.

All source code files written for the framework or that operate within the framework must contain a “file-level” docblock at the top of each file and a “class-level” docblock immediately above each class. Below are examples of such docblocks.

/**
 * Short description for file
 *
 * Long description for file (if any)...
 *
 * @copyright  2007 ABC, Inc.
 * @author     jdeveloper
 * @version    SVN: $Id:$
 * @link       http://intranet/docs/file_name
 * @since      File available since Release 1.2.0
 */

PhpDoc tags are very much like JavaDoc tags in Java. Tags are only processed if they are the first thing in a DocBlock line, for example:

/**
 * Tag example.
 * @author this tag is parsed, but this @version is ignored
 * @version 1.0 this tag is also parsed
 */

For docblocks within the CakePHP framework, always include the appropriate package, subpackage, and SVN keywords ($) as shown below:

/**
 * Short description for file
 *
 * Long description for file (if any)...
 *
 * @package      abc
 * @subpackage   abc.controllers
 * @author       jdeveloper
 * @version      $Revision$
 * @modifiedby   $LastChangedBy$
 * @lastmodified $Date$
 */

Note: The $ SVN keywords will be automatically updated by Subversion when the svn:keywords property is added to the file. Whenever creating a new PHP file to add to the Subversion repository, be sure to add the property like so:

In Shell:
svn propset svn:keywords "HeadURL Revision LastChangedBy Date" file_name.php

In Eclipse PDT (with Subversive):
1. Right click file -> Team -> Set Property...
2. Enter Property name: "svn:keywords"
3. Enter Property content: "HeadURL Revision LastChangedBy Date"

If a function / method may throw an exception, use @throws:

/**
 * @throws exception [description]
 */

Leave a Reply

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