PHP Code Style Guidelines

This document proposes a set of standards for PHP coding style.
From a culmination of experiments with various coding conventions, and
research into other coding standards, I have chosen these convensions
as the most suitable for my development projects.

Benefits
What are the benefits of documenting a coding style guide?

  • Increase consistency of produced code
  • Reduce cost of maintenance
  • Reduce cost of extension

Code Comments

Comment all functions and methods using phpDocumentor syntax.

phpDocumentor (http://www.phpdoc.org/)
/**
 * phpDocumentor comments can look like this, but usually, there's more
 * to is than this.
 */

Single Line Comments

# Do not use Perl-style comments

// Use double-slash comments instead
// A few lines can be commented like this just fine.

File Headers

Each PHP file, except for templates, should have a header that shows the file
name, copyright information, contact email, the file's authors, CVS keyword,
and the application license summary. For instance:

<?php
    /***********************************************************************
                                  filename.php
                               -------------------
        begin              :
      Sun July 18 2004

        copyright          :
      (C) 2004 Moxley Data Systems
        email              :
      support@moxleydata.com
        authors            :
      Your Name, Another Name
      

        $Id: index.main.php,v 1.1 2005/01/31 07:38:04 moxley Exp $
      
     ***********************************************************************/
      
    /***********************************************************************
     *
     *   This program is free software; you can
  redistribute it and/or

     *   modify it under the terms of the GNU General
  Public License as
     *   published by the Free Software Foundation;
  either version 2 of the
     *   License, or (at your option) any later
  version.
     *

     ***********************************************************************/
...

Notice how the comments are indented from the opening PHP tag. See below for
more guidelines on indentation.
Code Layout and Spacing
Basic Indentation
Normally all PHP code starts one indentation from the left. The opening PHP
tag stars at column zero (0), but the PHP code stars one indentation in.
<?php

// WRONG:
// Code should not start on the zero column.
$colors = array("red", "green", "blue");

for ($i=0; $i < count($colors); $i++ )
{
    print "$colors[$i]<br />\n";
}

?>
<?php

    // CORRECT:
    // To make your code more readable, start it at one
indentation from the left.

    $colors = array("red", "green",
"blue");
    for ($i=0; $i < count($colors); $i++ )
    {

        print "$colors[$i]<br
/>\n";
    }

?>
Opening and Closing Brackets

Each bracket goes on its own line.

// WRONG:
// Not enough vertical spacing
foreach ($quantities as $sku=>$qty) {
    $inv = $inventory[$sku];

    if( $qty > $inv ) {
        $overages[$sku] = $qty - $inv;
    }
}

// CORRECT:

// Horizontal AND vertical space makes code more readable
foreach ($quantities as $sku=>$qty)
{
    $inv = $inventory[$sku];
    if( $qty > $inv )

    {
        $overages[$sku] = $qty - $inv;
    }
}

Token Spacing
Tokens are separated by spaces, except for opening and closing parentheses with
their first inner tokens.

Line Length
Try to keep lines to no more than 80 columns. Better to keep it under. However,
for string literals, it is okay to let the line go as long as you want.
If a line is over 80 columns wide, break it up assignments like this:
// Each argument goes on a separate line, one indent
in
$output["resultsNav"] = $this->getResultsNav(

    $output["count"], 
    $offset,
    $params["maxResults"], 
    $params["maxLinks"],

    array(
        "action"     =>"listByCategory",
        "maxResults" =>$params["maxResults"],
        "Categories" =>implode(",", $cleanIncludeIDs)

    )
);
All PHP files should end with a single newline character. The PHP parser ignores
this character, so you don't have to worry about sending characters prematurely
to the output.

Column Alignment
Sometimes it is helpful to align parts of similar lines like this:
// Line up here -------------->|<-------

define("XVEND_ADMIN_TPL_ROOT", XVEND_ADMIN);
define("XVEND_SHOP_TPL",       XVEND_APP."/shop/tpl");
define("XVEND_TEST_ROOT",      XVEND_APP."/tests");

define("XVEND_BIN",            XVEND_INSTALL."/bin");
define("XVEND_CONF",          
XVEND_INSTALL."/conf");

define("MAX_CATEGORY_DEPTH",   10);
Editor Settings
Tabs
Set your editor's tab setting to 2 or 4, or whatever you want your basic indent
width to be. Use tab characters instead of spaces for indentation.
Line Endings
Set up your editor to save files in UNIX format. In a UNIX formated text file,
each line is separated with a newline character. DOS text files separate lines
with a carriage return and linefeed character combination. Macintosh text files
use a carriage return character.

Naming Conventions
Identifiers should always describe what they are or what they do. Avoid extensive
abbreviation.
// WRONG:
// These don't give us any indication as to what they are for
function doIt() {}
$a = 1;

Instead, name your identifiers like this:

// CORRECT:
// Communicate what the identifiers are used for
function getName() {}
function arrayToString() {}
$actionStr = "editRecord";

Constants
Constants are always upper-case. Each word in the constant name should be separated
by an underscore (_).
define("MAX_CATEGORY_DEPTH",   10);
define("XVEND_ADMIN_TPL_ROOT", "/home/site1/htdocs/admin");

Local Variables

Local variable names should use the "studly caps" convension and start
with a lower-case letter.
// WRONG
$start_column = 1;

// CORRECT
$startColumn = 1;

Global Variables
Global variables should be upper-case. Each word in the constant name should
be separated by an underscore (_).
// WRONG
function getConfiguration()
{
    global $app_environment;

...
// CORRECT
function getConfiguration()
{
    global $APP_ENVIRONMENT;
...

Functions
Functions should start with a lower-case letter and use the "studly caps"
convention. Start the function name with a verb unless it is plain to see what
it does without a verb.
// WRONG:
function parse_configuration()
{

    ...
}
// CORRECT:
function parseConfiguration()
{
    ...

}
Classes
Class names should start with an upper-case letter and use the "studly
caps" convention.
// WRONG
class shopping_cart

{
    ...
}
// CORRECT
function ShoppingCart()
{

    ...
}
Private Member Variables
Private member variables of classes should begin with an underscore.
// WRONG
var $secretKey;

// CORRECT
var $_secretKey;

Files
Class file: ClassName.class.php
Function library: name.lib.php
Script: scriptname.php

Numerals Within Names
Avoid putting numerals within identifiers.
// WRONG
function string2Array()
{
    ...
}

// CORRECT
function stringToArray()
{
    ...
}

Variables, Data Types

Globals vs. Local
Avoid global variables. Instead, use function arguments to pass variables to
functions and methods, or pass variables as arguments to class constructors.

// WRONG
class Cart
{
     function save()

     {
          global $databaseConnection;

          // Save the cart to a database
          ...

     }
}

// CORRECT
class Cart
{

     var $database;

     function Cart(&$database)
     {
          $this->database =&
$database;

     }

     function &getDatabase()
     {
          return $this->database;

     }

     function save()
     {
          $db =& $this->getDatabase();

          // Save the cart to a database
          ...
     }
}

Initialization Before Blocks
For variables that will be populated within a control block, be sure to initialize
the variable before the block.
// WRONG
if( $user == $_REQUEST['username'] )
{

     $correctUser = TRUE;
}

// WRONG
foreach( $userIds as $id )
{

     $idArray[] = "id#" . $id;
}
// CORRECT
$correctUser = FALSE;
if( $user == $_REQUEST['username'] )

{
     $correctUser = TRUE;
}

// CORRECT
$idArray = array();

foreach( $userIds as $id )
{
     $idArray[] = "id#" . $id;
}
Boolean Functions and Variables

Use PHP's boolean type instead of 0 and 1 when you function is returning a boolean
result.
Checking Variables and Associative Array elements using isset()
If you are not sure that a variable will be set, check it with isset(). The
same applies (and is probably more common) to associative array (hash) elements.
This document calls for you to open PHP error reporting to report ANYTHING that
the parser finds, and there should be no error reporting messages when your
code runs.
// WRONG
if( $_REQUEST["subscribeCheckbox"] )

// CORRECT
if( isset($_REQUEST["subscribeCheckbox"]) )

PHP-Specific
magic_quotes_gpc
Be sure to configure your copy of PHP to turn magic_quotes_gpc to 'off'. The
magic_quotes_gpc 'feature' increases the complexity and unpredictability of
larger applications, and encourages insecure coding practices by inexperienced
developers.

Error Reporting
Error reporting should be configured so that all message types may be invoked.
PHP error messages should always be appended to a log. In production environments,
no PHP error messages should be output to the user.
Apache configuration:
php_value magic_quotes_gpc 0             #
Don't let PHP taint your input data
php_value error_log        /home/site1/logs/phperror.log
php_value error_reporting  2047          #
Report everything

php_value log_errors       1
php_value short_open_tags  0

PHP Tags
Do not use short open tags. Always use <?php instead of <?.
This increases the portability and makes your PHP templates more compatible
with XML parsers.

White Space Pollution
Be careful to avoid letting your application output to the client before it
is supposed to. All PHP files, aside from templates, should start with <?php,
as the first set of characters in the file. There should be no spaces prior
to the opening tag. It is OK (and required) to append a newline character at
the end of all PHP files. The PHP parser will not output this character if it
is at the end of the file.
Functions
Define functions (including methods) to pass object arguments by reference.

function convertToString(&$cart)
{

    ...
}

Classes
Every class definition goes in its own file. One class per file. The file name
includes the class name.

<?php
    // Cart.class.php

    class Cart
    {
        function Cart()
        {
            ...

        }

    }
?>

When instantiating a class, use the Reference operator to get the reference
to the original object.
Declare all class variables. Do not use class variables without declaring them
in the class definition.
Control Statements
Switch Statements

End case statements with the break keyword, even
if the case has a return statement:

switch($selection)
{
    case '1':
        return FALSE;

        break;
    case '2':
        return TRUE;
        break;
    default:
        return FALSE;
}
Operating System

Path Delimiter
Take care in specifying the correct path delimiter character and path separator
character. Define a constant to hold the delimiter character for the operating
system, and refer to that constant:

if ($osType == "windows")
{
    define(PATH_DELIMITER, "\\");

    define(PATH_SEPARATOR, ";");
}
else
{
    define(PATH_DELIMITER, "/");

    define(PATH_SEPARATOR, ":");
}
...
ini_set("include_path", "." . PATH_SEPARATOR . $classesDir);

...
$classFile = "controllers" . PATH_DELIMITER . $className . ".class.php";
include_once($classFile);

 

Error Handling
HTML and SQL
Escaping HTML
All dynamic output to an HTML stream should be escaped unless such output is
supposed to be HTML.
<!-- WRONG -->
<title><?php print $output["title"]; ?></title>

<!-- CORRECT -->
<title><?php print htmlspecialchars($output["title"]); ?></title>

It will help to create "shortcut" functions to make escaping HTML
easier:
<?php

    
    function h($stringVal)
    {
        return htmlspecialchars($stringVal);
    }
    
    function ph($stringVal)

    {
        print h($stringVal);
    }
?>
...
<title><?php ph($output["title"]); ?></title>

Escaping SQL
All dynamic data injected into an SQL query must be escaped.
// WRONG
$query = "SELECT name FROM contact WHERE id=$id";

// CORRECT
$query = "SELECT name FROM contact WHERE id=" . intval($id);

// CORRECT
$query = "SELECT password FROM user WHERE username='" . addslashes($username)
. "'";
As with HTML escaping, it will help to create "shortcut" functions
to make escaping SQL easier:


function dq($stringVal)
{
    return "'" . addslashes($stringVal)
. "'";
}

...

$query = "SELECT password FROM user WHERE
username=" . dq($username);

Valid XHTML

Strive to produce valid XHTML output.
Quote tag attributes with the double-quote character ("):
<!-- WRONG -->
<input type=text name=firstName>

<!-- WRONG -->
<input type='text' name='firstName'>

<!-- CORRECT -->
<input type="text" name="firstName" />

Indentation and Layout
HTML should be indented for easy readability. Use two spaces for indentation.
<!-- CORRECT -->

<html>
  <head>
    <title>Edit Product</title>
  </head>
  <body>

    <h1>Edit Product</h1>
  </body>
</html>