PHP Coding Standards
General
Your development machine should be on PHP 7.4 or better. PHP 8.0 is preferred.
Use our package.json to automatically lint your code with PHPCS.
Indentation 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.
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;
.
Casting
Put a space between the (type) and the $variable in a cast: (int) $mynumber
.
Control Stuctures
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. The opening curly should be on the same line as the opening statement, preceded by one space. The closing curly should be on a line by itself and indented to the same level as the opening statement.
if, elseif, else:
if (condition1 || condition2) {
action1;
}
elseif (condition3 && condition4) {
action2;
}
else {
defaultaction;
}
(Note: Don't use "else if" -- always use elseif.)
switch:
switch (condition) {
case 1:
action1;
break;
case 2:
action2;
break;
default:
defaultaction;
}
Note: Each case statement must be followed by a blank line.
do-while:
do {
actions;
} while ($condition);
Line Length and Wrapping
In general, all lines of code should not be longer than 80 characters.
Lines containing longer function names, function/class definitions, variable declarations, etc are allowed to exceed 80 characters.
Control structure conditions may exceed 80 characters, 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);
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.
Anonymous functions should have a space between "function" and its parameters, as in the following example:
array_map(function ($item) use ($id) {
return $item[$id];
}, $items);
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);
Arrays
Arrays should be formatted using short array syntax with a space separating each element (after the comma), and spaces around the => key association operator, if applicable:
$some_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'] = [
'#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, and leads to cleaner diff's.
Quotes
Single quote strings should be used by default. Their use is recommended except in two cases:
Deliberate in-line variable interpolation, e.g.
"<h2>$header</h2>"
.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.
<?php
$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.
<?php
$string = "Foo $bar";
?>
Like all other operators, when using the concatenating assignment operator ('.='), use a space on each side as with the assignment operator:
<?php
$string .= 'Foo';
$string .= $bar;
$string .= baz();
?>
Comments
Please refer to this Doxygen and comment formatting conventions page.
Including Code
Anywhere you are including a class file you should use the PSR-4 standard for autoloading classes via filenames. This starts with creating a class in a module and defining a namespace using the namespace
keyword followed by a name at the top of your class file.
The convention for Drupal namespaces always begins with Drupal\<module name>\...
- It MUST contain a top level vendor namespace, in this case
Drupal
- It MAY contain one or more sub-namespaces which is usually your module name (E.g.:
mymodule
) - It MUST contain an ending class name (E.g.:
Controller
)
The final namespace would be Drupal\mymodule\Controller
. This namespace should also translate to a file path. So, Drupal\mymodule\Controller
would be located in [path_to_custom_modules]/mymodule/src/Controller/Controller.php
Note: The
/src/
subfolder is omitted from the namespace and the path to the custom module folder is usually<app root>/modules/custom
. Though not our standard practice, the custom module folder can be located elsewhere in the document root due to Drupal's auto-discovery features.
Once we have defined the namespace if we want to use it elsewhere we must do so with the use
keyword followed by the namespace and use the short name of the class when calling it. For example:
namespace Drupal\mymodule\Tests\Foo;
use Drupal\simpletest\WebTestBase;
/**
* Tests that the foo bars.
*/
class BarTest extends WebTestBase {
Note: When calling global classes like the PHP-Exception class or a Drupal core class in a namespaced file you should use the backslash to disambiguate (E.g.:
new \Exception();, \Drupal::messenger()->addMessage();
)
Some other useful tips:
- Specify a single
use
statement per line and do not specify multiple classes in a singleuse
statement. - There is no particular order they need to be in but take readability into account and make a sensible decision.
PHP Code Tags
Always use <?php ?>
to delimit PHP code, not the shorthand, <? ?>
.
When developing for Drupal, the ?>
at the end of code files is purposely omitted. This includes for 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: prepend.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. Our coding standards require them, even at the end of code blocks. In particular, for one-line PHP blocks:
// bad
<?php print $tax ?>
// good
<?php print $tax; ?>
Example URLs
Use "example.com" for all example URLs, per RFC 2606.
Naming Conventions
Functions and variables
Functions 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.
Variables should be named using lowercase, and words should be separated either with uppercase characters (example: $lowerCamelCase
) or with an underscore (example: $snake_case
). Be consistent; do not mix camelCase and snake_case variable naming inside a file.
Constants
Constants should always be all-uppercase, with underscores to separate words. (This includes pre-defined PHP constants like
TRUE
,FALSE
, andNULL
.)Module-defined constant names should also be prefixed by an uppercase spelling of the module that defines them.
In Drupal 8 and later, constants should be defined using the
const
PHP language keyword (instead of define()), because it is better for performance:/** * Indicates that the item should be removed at the next general cache wipe. */ const CACHE_TEMPORARY = -1;
Note that const does not work with PHP expressions. define() should be used when defining a constant conditionally or with a non-literal value:
if (!defined('MAINTENANCE_MODE')) { define('MAINTENANCE_MODE', 'error'); }
Global Variables
If you need to define global variables, their name should start with a single underscore followed by the module/theme name and another underscore.
Classes
All standards related to classes and interfaces, including naming, are covered on http://drupal.org/node/608152 instead of here.