Backdrop's PHP coding standards mirror those of Drupal.

Indenting and Whitespace #

Use an indent of 2 spaces, with no tabs.

Lines should have no trailing whitespace at the end.

Files should be formatted with \n as the line ending (Unix line endings), not \r\n (Windows line endings).

All text files should end in a single newline (\n). This avoids the verbose "\ No newline at end of file" patch warning and makes patches easier to read since it's clearer what is being changed when lines are added to the end of a file.

The /** @file */ docblock at the beginning of a PHP file should not be preceded by a blank line, but should be followed by a blank line. Files should begin as follows:

<?php
/**
* @file
* Foo file does bar.
*/

/**
* Implements hook_baz().
*/
function...

Operators #

All binary operators (operators that come between two values), such as +, -, =, !=, ==, >, etc. should have a space before and after the operator, for readability. For example, an assignment should be formatted as $foo = $bar; rather than $foo=$bar;. Unary operators (operators that operate on only one value), such as ++, should not have a space between the operator and the variable or number they are operating on.

Casting #

Put a space between the (type) and the $variable in a cast: (int) $my_number.

Control Structures #

Control structures include if, for, while, switch, etc. Here is a sample if statement, since it is the most complicated of them:

if (condition1 || condition2) {
  action1;
}
elseif (condition3 && condition4) {
  action2;
}
else {
  defaultaction;
}

(Note: Don't use "else if" -- always use elseif.)

Control statements should have one space between the control keyword and opening parenthesis, to distinguish them from function calls.

Always use curly braces even in situations where they are technically optional. Having them increases readability and decreases the likelihood of logic errors being introduced when new lines are added.

For switch statements:

switch (condition) {
  case 1:
    action1;
    break;

  case 2:
    action2;
    break;

  default:
    defaultaction;
}

For do-while statements:
do {
  actions;
} while ($condition);

Alternate control statement syntax for templates

In templates, the alternate control statement syntax using colons instead of brackets is encouraged. Note that there should not be a space between the closing paren after the control keyword, and the colon, and HTML/PHP inside the control structure should be indented. For example:

<?php if (!empty($item)): ?>
  <?php print $item; ?>
<?php endif; ?>

<?php foreach ($items as $item): ?>
  <?php print $item; ?>
<?php endforeach; ?>

Line length and wrapping #

The following rules apply to code. See Doxygen and comment formatting conventions for rules pertaining to comments.

  • In general, all lines of code should not be longer than 80 chars.
  • Lines containing longer function names, function/class definitions, variable declarations, etc are allowed to exceed 80 chars.
  • Control structure conditions may exceed 80 chars, if they are simple to read and understand:
    if ($something['with']['something']['else']['in']['here'] == mymodule_check_something($whatever['else'])) {
      ...
    }
    if (isset($something['what']['ever']) && $something['what']['ever'] > $infinite && user_access('galaxy')) {
      ...
    }
    // Non-obvious conditions of low complexity are also acceptable, but should
    // always be documented, explaining WHY a particular check is done.
    if (preg_match('@(/|\\)(\.\.|~)@', $target) && strpos($target_dir, $repository) !== 0) {
      return FALSE;
    }
  • Conditions should not be wrapped into multiple lines.
  • Control structure conditions should also NOT attempt to win the Most Compact Condition In Least Lines Of Code Award™:
    // DON'T DO THIS!
    if ((isset($key) && !empty($user->uid) && $key == $user->uid) || (isset($user->cache) ? $user->cache : '') == ip_address() || isset($value) && $value >= time())) {
      ...
    }

    Instead, it is recommended practice to split out and prepare the conditions separately, which also permits documenting the underlying reasons for the conditions:
    // Key is only valid if it matches the current user's ID, as otherwise other
    // users could access any user's things.
    $is_valid_user = (isset($key) && !empty($user->uid) && $key == $user->uid);

    // IP must match the cache to prevent session spoofing.
    $is_valid_cache = (isset($user->cache) ? $user->cache == ip_address() : FALSE);

    // Alternatively, if the request query parameter is in the future, then it
    // is always valid, because the galaxy will implode and collapse anyway.
    $is_valid_query = $is_valid_cache || (isset($value) && $value >= time());

    if ($is_valid_user || $is_valid_query) {
      ...
    }

Note: This example is still a bit dense. Always consider and decide on your own whether people unfamiliar with your code will be able to make sense of the logic.

Function Calls #

Functions should be called with no spaces between the function name, the opening parenthesis, and the first parameter; spaces between commas and each parameter, and no space between the last parameter, the closing parenthesis, and the semicolon. Here's an example:

$var = foo($bar, $baz, $quux);

As displayed above, there should be one space on either side of an equals sign used to assign the return value of a function to a variable. In the case of a block of related assignments, more space may be inserted to promote readability:
$short         = foo($bar);
$long_variable = foo($baz);

Function Declarations #

function funstuff_system($field) {
  $system["description"] = t("This module inserts funny text into posts randomly.");
  return $system[$field];
}

Arguments with default values go at the end of the argument list. Always attempt to return a meaningful value from a function if one is appropriate.

Class Constructor Calls #

When calling class constructors with no arguments, always include parentheses:

$foo = new MyClassName();

This is to maintain consistency with constructors that have arguments:
$foo = new MyClassName($arg1, $arg2);

Note that if the class name is a variable, the variable will be evaluated first to get the class name, and then the constructor will be called. Use the same syntax:
$bar = 'MyClassName';
$foo = new $bar();
$foo = new $bar($arg1, $arg2);

Type Hinting #

Whenever possible, function and method parameters should specify their data types using type hinting. Because type hinting cannot be used with scalar types such as int or string (to allow backwards-compatibility with PHP versions < 7), this only comes into play when arguments are arrays or objects.

class MyClass {
  /**
   * First parameter must be an object implementing the OtherClassInterface.
   */
  public function test(OtherClassInterface $otherClass) {
      echo $otherClass->var;
  }


  /**
   * First parameter must be an array.
   */
  public function test_array(array $input_array) {
    print_r($input_array);
  }

When using type hinting on classes, it is recommended to specify the particular interface the class implements rather than the class name itself. This allows other classes that implement the same interface to be passed in, allowing for easier swappability.

Arrays #

PHP 5.4 introduced support for the shorthand format for arrays (see https://www.php.net/manual/en/migration54.new-features.php). Since Backdrop CMS supports PHP 5.3.2 (see System Requirements), the long format is to be used with arrays:

  • $a = array(1, 2, 3, 4);
  • $a = array('one' => 1, 'two' => 2, 'three' => 3, 'four' => 4);

Arrays should be formatted with a space separating each element (after the comma), and spaces around the => key association operator, if applicable:

$some_array = array('hello', 'world', 'foo' => 'bar');

Note that if the line declaring an array spans longer than 80 characters (often the case with form and menu declarations), each element should be broken into its own line, and indented one level:
$form['title'] = array(
  '#type' => 'textfield',
  '#title' => t('Title'),
  '#size' => 60,
  '#maxlength' => 128,
  '#description' => t('The title of your node.'),
);

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.

Quotes #

Backdrop does not have a hard standard for the use of single quotes vs. double quotes. Where possible, keep consistency within each module, and respect the personal style of other developers.

With that caveat in mind: single quote strings are known to be faster because the parser doesn't have to look for in-line variables. Their use is recommended except in two cases:

  1. In-line variable usage, e.g. "<h2>$header</h2>".
  2. Translated strings where one can avoid escaping single quotes by enclosing the string in double quotes. One such string would be "He's a good person." It would be 'He\'s a good person.' with single quotes. Such escaping may not be handled properly by .pot file generators for text translation, and it's also somewhat awkward to read.

String Concatenations #

Always use a space between the dot and the concatenated parts to improve readability.

$string = 'Foo' . $bar;
$string = $bar . 'foo';
$string = bar() . 'foo';
$string = 'foo' . 'bar';

When you concatenate simple variables, you can use double quotes and add the variable inside; otherwise, use single quotes.
$string = "Foo $bar";

When using the concatenating assignment operator (.=), use a space on each side as with the assignment operator:
$string .= 'Foo';
$string .= $bar;
$string .= baz();

Comments #

Standards for documenting functions, classes, and methods are discussed on the separate Code Documentation Standards page.

Comments within functions and methods should use capitalized sentences with punctuation. All caps are used in comments only when referencing constants, e.g., TRUE. Comments should be on a separate line immediately before the code line or block they reference. For example:

// Unselect all other checkboxes.

If each line of a list needs a separate comment, the comments may be given on the same line and may be formatted to a uniform indent for readability.

C style comments (/* */) and standard C++ comments (//) are both fine.

Including Code #

Anywhere you are unconditionally including a class file, use require_once(). Anywhere you are conditionally including a class file (for example, factory methods), use include_once(). Either of these will ensure that class files are included only once. They share the same file list, so you don't need to worry about mixing them - a file included with require_once() will not be included again by include_once().

Note: include_once() and require_once() are statements, not functions. You don't need parentheses around the file name to be included.

When including code from the same directory or a sub-directory, start the file path with ".":
include_once ./includes/mymodule_formatting.inc

When including a file relative to the root of the installation (such as a core/includes file), use BACKDROP_ROOT:
require_once BACKDROP_ROOT . '/core/includes/cache.inc';``

PHP Code Tags #

Always use <?php ?> to delimit PHP code, not the shorthand, <? ?>. This is the most portable way to include PHP code on differing operating systems and setups.

Note that the ?> at the end of code files is purposely omitted. This includes module and include files. The reasons for this can be summarized as:

  • Removing it eliminates the possibility for unwanted whitespace at the end of files which can cause "header already sent" errors, XHTML/XML validation issues, and other problems.
  • The closing delimiter at the end of a file is optional.
  • PHP.net itself removes the closing delimiter from the end of its files (example: site.inc), so this can be seen as a "best practice."

Semicolons #

The PHP language requires semicolons at the end of most lines, but allows them to be omitted at the end of code blocks. Backdrop coding standards require them, even at the end of code blocks. In particular, for one-line PHP blocks:

<?php print $tax; ?> -- YES
<?php print $tax ?> -- NO

Naming Conventions #

Functions and variables

Functions and variables should be named using lowercase, and words should be separated with an underscore. Functions should in addition have the grouping/module name as a prefix, to avoid name collisions between modules.

function my_module_example_function() {
  $my_variable = 'Some example string';
  return $my_variable;
}

Persistent Variables

Persistent variables (variables/settings defined using Backdrop's config functions, e.g., config_get()/config_set()) should be named using all lowercase letters, and words should be separated with an underscore.

config_set('my_module.setting', 'foo', TRUE);
$value = config_get('my_module.setting', 'foo');

Persistent variables that use Backdrop's state functions, e.g., state_get()/state_set() should use the grouping/module name as a prefix, to avoid name collisions between modules.

state_set('my_module_foo', TRUE);
$value = state_get('my_module_foo');

See the documentation for state_get for details about config_*() versus state_*() functions.

Constants

Constants should always be all-uppercase, with underscores to separate words. This includes pre-defined PHP constants like TRUE, FALSE, and NULL. Module-defined constant names should also be prefixed by an uppercase spelling of the module that defines them.

define('MY_MODULE_FLAG_A', 0);
define('MY_MODULE_FLAG_B', 1);

Global Variables

Any use of custom globals is discouraged. Instead use a function that wraps a static variable. An alternative to global variables:

function my_module_set_variable($value = NULL) {
  static $stored_value = NULL;
  if (isset($value)) {
    $stored_value = $value;
  }
  return $stored_value;
}
function my_module_get_variable() {
  return my_module_set_variable();
}

// When setting the variable:
my_module_set_variable('Some value');

// When getting the variable:
$value = my_module_get_variable();

If you absolutely need to define global variables, their name should start with a single underscore followed by the module/theme name and another underscore.
$_GLOBALS['_my_module_variable'] = 'foo';

Classes

Classes should be named using "UpperCamelCase" (with some exceptions: see below). For example:

abstract class DatabaseConnection extends PDO {

Class methods and properties should use "lowerCamelCase":
public $lastStatement;

public function getLastStatement() {
  ...
}

Class names themselves should adhere to these rules:
  1. Class names should not have "Class" in the name.
  2. Interfaces should always have the suffix "Interface".
  3. Test classes should always have the suffix "Test".

There are some exceptions for plugin names that are "grandfathered" in (e.g., Views plugins); see the detailed discussion of Object-Oriented Code below.

File names

Template files must always end in .tpl.php

PHP files should either end in .module or .inc.

Ideally, all run-time hooks should be defined in the .module file. If the hook you are implementing is an info hook and includes a 'file' directive, the associated functions should be placed into a separate include file. Examples of this include my_module.theme.inc, my_module.admin.inc, my_module.token.inc, etc. Moving these sections of related code will decrease the amount of code in the .module file, making run-time execution slightly faster, and it will make working with these files easier for all contributors. It will also have the additional benefit of making it it clear from the file structure what parts of the CMS each module will affect. For example, I can tell from the file structure below (without reading any code) that the module has an administration section, builds its own pages, and uses the theme system.

BACKDROP_ROOT/modules
    my_module
        README.md
        my_module.info
        my_module.module
        my_module.theme.inc
        my_module.admin.inc
        my_module.pages.inc
        css
            my_module.css
            my_module.admin.css
            my_module.theme.css
        js
            my_module.js
            my_other_js.js
        templates
            my_module_display.tpl.php
            another_display.tpl.php
        config
            my_module.settings.json
            my_module.typea.json
            my_module.typeb.json
            my_module.typec.json
        libraries
            libname
                libname.php
                libname.css
                libname.js
        includes
            my_module.class.inc
        modules
            submodule
                submodule.info
                submodule.module
        tests
            my_module.tests.info
            my_module.test

All documentation files should have the file name extension ".md" to make viewing them on Github easier. Also, the file names for such files should be all-caps (e.g. README.md instead of readme.md) while the extension itself is all-lowercase (i.e. md instead of MD).

Examples: README.md, INSTALL.md, TODO.md, CHANGELOG.md etc.

Object-Oriented Code#

Backdrop follows common PHP conventions for object-oriented code, and established industry best practices. As always, though, there are Backdrop-specific considerations.

Declaring Classes

How to define and where to place your classes?

Classes will be autoloaded; your classes should be declared in hook_autoload_info(), e.g.,

<?php
/**
 * Implements hook_autoload_info().
 */
function mymodule_autoload_info() {
  return array(
   
'MyClass' => 'includes/my_class.class.inc',
  );
}
?>

Class names should have UpperCamelCase naming (see more below). For the file name, convert the class name to lower_snake_case, then add ".class.inc". Thus, for example, class MyCoolThing would be defined in file my_cool_thing.class.inc.

Class files should be included in a subdirectory of the module, typically includes.

Best practices include having one class or interface or trait per file. That file should be named for the class, such that the file name for FooInterface would be foo_interface.class.inc.

Exceptions are:

  • An interface and its implementation can be placed in the same file. You should use the interface name to derive the file name.
  • A series of small classes (such as Exception subclasses) can be placed in a single file. Note, though, that each class will need its own line in the hook_autoload_info() function.

For historical reasons, many classes in Backdrop do not fully follow these guidelines. They have been grandfathered in for backwards compatibility. Newly created classes should follow the guidelines.

Indenting and Whitespace

Please refer to the Indenting section (above) for basic indenting that are applicable in OO as well. Here are some additional guidelines that are specific to OO.

Leave an empty line between start of class/interface definition and property/method definition:

<?php
class GarfieldTheCat implements FelineInterface {
 
// Leave an empty line here.
 
public function meow() {
...
...
...
?>

Leave an empty line between the end of property definitions and the start of method definitions:

<?php
...
...
...
  protected
$lasagnaEaten = 0;
 
// Leave an empty line here.
  /**
   * Return the sound of a cat.
   */
 
public function meow() {
    return
t('Meow!');
  }
?>

Leave an empty line between the end of the last method and the end of the class definition:

<?php
class GarfieldTheCat implements FelineInterface {
...
...
...
  public function
eatLasagna($amount) {
   
$this->lasagnaEaten += $amount;
  }
 
// Leave an empty line here.
}
?>

Docblocks

Include docblock-style comments before every class and, within the class, before every declared property or method.

<?php
/**
 * class that represents a person who folds paper.
 */
class Paperfolder extends Artist {
 
/**
   * stores the folded paper state.
   */
 
private $paperState = array();

 
/**
   * Fold the paper into something.
   */
 
public function foldPaper($into_what) {
    ...
  }

 
/**
   * Unfold the paper.
   */
 
public function unfoldPaper() {
    ...
  }

}
?>

For methods of a class that override a parent class method, use {@inheritdoc} in the docblock comment:

<?php
/**
 * Interface for an Artist class.
 */
class Artist {
 
/**
   * Create a piece of art from a medium.
   */
 
public function createArt($medium);

}

/**
 * Defines a particular type of artist.
 */
class Painter implements Artist {
 
/**
   * {@inheritdoc}
   */
 
public function createArt($medium) {
    ...
  }

}
?>

Naming conventions

Classes and interfaces should use UpperCamel naming.

Methods and class properties should use lowerCamel naming.

If an acronym is used in a class or method name, make it CamelCase too (SampleXmlClass, not SampleXMLClass).

Classes should not use underscores in class names unless absolutely necessary to derive names inherited class names dynamically. That is quite rare, especially as Backdrop does not mandate a class-file naming match.

Names should not include "Backdrop".

Class names should not have "Class" in the name.

Interfaces should always have the suffix "Interface".

Test classes should always have the suffix "Test".

Protected or private properties and methods should not use an underscore prefix.

Classes and interfaces should have names that stand alone to indicate what they do. They should read well, and should be short as possible without losing functionality information or leading to ambiguity.

Stand-alone name examples:

Good name Bad names
QueryCondition Condition (ambiguous)
DatabaseQueryCondition (Database doesn't add to understanding)
LocalFileTransfer Local (ambiguous)
CacheDatabaseDriver Database (ambiguous/misleading)
DatabaseDriver (ambiguous/misleading)
Entity
EntityInterface
BackdropEntity (unnecessary words)
EntityClass (unnecessary words)

A complete example of class/interface/method names:

<?php
interface FelineInterface {
 
// Leave an empty line here.
  /**
   * Make a sound.
   */
 
public function meow();
 
// Leave an empty line here.
  /**
   * Consume some comestibles.
   */
 
public function eatLasagna($amount);
 
// Leave an empty line here.
}
 
// Leave an empty line here.
/**
 * Class for a particular commercially profitable cat.
 */
class GarfieldTheCat implements FelineInterface {
 
// Leave an empty line here.
  /**
   * Stores the amount of lasagna eaten by the cat.
   */
 
protected $lasagnaEaten = 0;
 
// Leave an empty line here.
  /**
   * {@inheritdoc}
   */
 
public function meow() {
    return
t('Meow!');
  }
 
// Leave an empty line here.
  /**
   * Consume some comestibles.
   */
 
public function eatLasagna($amount) {
   
$this->lasagnaEaten += $amount;
  }
 
// Leave an empty line here.
}
?>

Naming conventions exceptions

There are some established exceptions to the class and file naming conventions above, which are modules ported from Drupal 7 that already have established conventions for how their plugin classes are named: Views (which is now in Backdrop Core) being one of the commonest cases. For example, Views plugins use lower_snake_case for class and file names; an example would be declared like this:

<?php
/**
 * Class to define a style plugin handler.
 */
class mymodule_views_plugin_style_table extends views_plugin_style_table {
  ...
}
?>

and the file would be named mymodule_views_plugin_style_table.inc.

Use of interfaces

The use of an interface definition that is separate from an implementing class is strongly encouraged because it allows more flexibility in extending code later. A separate interface definition also neatly centralizes documentation making it easier to read. All interfaces should be fully documented according to established documentation standards.

If there is even a remote possibility of a class being swapped out for another implementation at some point in the future, split the method definitions off into a formal Interface. A class that is intended to be extended must always provide an Interface that other classes can implement rather than forcing them to extend the base class.

Visibility

All methods and properties of classes must specify their visibility: public, protected, or private. The PHP 4-style "var" declaration must not be used.

The use of public properties is strongly discouraged, as it allows for unwanted side effects. It also exposes implementation-specific details, which in turn makes swapping out a class for another implementation (one of the key reasons to use objects) much harder. Properties should be considered internal to a class and should be accessed via setter/getter functions.

Note that in Backdrop, for historical reasons, many properties are left public by default. Newly created classes should explicitly declare property visibility. It is possible that in Backdrop 2.0, some existing public properties may become private. If an existing class has setter/getter functions, you should use them instead of accessing default-public properties, as the latter have a high likelihood of becoming private in Backdrop 2.0.

Type hinting

PHP supports optional type specification for function and method parameters for classes and arrays. Although called "type hinting" it does make a type required, as passing an object that does not conform to that type will result in a fatal error.

  • DO specify a type when conformity to a specific interface is an assumption made by the function or method. Specifying the required interface makes debugging easier as passing in a bad value will give a more useful error message.
  • DO NOT use a class as the type in type hinting. If specifying a type, always specify an Interface. That allows other developers to provide their own implementations if necessary without modifying existing code.

Example:

<?php
// Correct:
function makeCatSpeak(FelineInterface $cat) {
  print
$cat->meow();
}

// Wrong:
function makeCatSpeak(GarfieldTheCat $cat) {
  print
$cat->meow();
}
?>

Instantiation

Creating classes directly is discouraged. Instead, use a factory function that creates the appropriate object and returns it. This provides two benefits:

  1. It provides a layer of indirection, as the function may be written to return a different object (with the same interface) in different circumstances as appropriate.
  2. PHP does not allow class constructors to be chained, but does allow the return value from a function or method to be chained.

Chaining

PHP allows objects returned from functions and methods to be "chained", that is, a method on the returned object may be called immediately. This is known as a "fluent interface." Here is an example:

<?php
// Unchained version
$result = db_query("SELECT title FROM {node} WHERE nid = :nid", array(':nid' => 42));
$title = $result->fetchField();

// Chained version
$title = db_query("SELECT title FROM {node} WHERE nid = :nid", array(':nid' => 42))->fetchField();
?>

As a general rule, a method should return $this, and thus be chainable, in any case where there is no other logical return value. Common examples are those methods that set some state or property on the object. It is better in those cases to return $this rather than TRUE/FALSE or NULL.

In the case where you have a fluent interface for a class and the code spans more than one line, the method calls should be indented with 2 spaces:

<?php
$query
= db_select('node')
  ->
condition('type', 'article')
  ->
condition('status', 1)
  ->
execute();
?>

Example URLs #

Use "example.com" for all example URLs, per RFC 2606.

Portions of this page based on Drupal PHP Coding Standards.