Skip to content

Coding Standards

A set of guidelines regarding naming conventions and document formatting to follow that dictate the writing style used when working with a specific programming language. It is easier for ourselves and for others who are reviewing our code to spot errors.

Why coding standards?

  • Readability
  • Maintainable code
  • Spot errors more easily
  • Encourages collective ownership

Formatting

Formatting standards are guidelines for writing and formatting code in Drupal projects use of whitespace, how to format control structures, and other aspects that affect your code's appearance and format.

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.

  • All blocks at the beginning of a PHP file should be separated by a blank line. This includes the /** @file */ block, the namespace declaration and the use statements (if present) as well as the subsequent code in the file. So, for example, a file header might look as follows:

php
<?php

namespace This\Is\The\Namespace;

use Drupal\foo\Bar;

/**
 * Provides examples.
 */
class ExampleClassName {

Or, for a non-class file (e.g., .module):

php
<?php

/**
 * @file
 * Provides example functionality.
 */

use Drupal\foo\Bar;

/**
 * Implements hook_help().
 */
function example_help($route_name) {

File endings

Use the Unix file ending, which is a single blank line at the end of each file. This is another thing most text editors can do for you! Just one line, no more, no less.

Line length

Lines should be 80 characters long. However, keep in mind that this is primarily for readability. If forcing your code to be broken up over multiple lines makes it less readable, then you should reconsider. This is especially true for conditions, which should never be wrapped onto multiple lines. Comment and documentation text, however, should always be 80 characters or under. Make sure that you have a ruler set up in your editor to show you where you’re going over, and you’ll never have to guess.

If you have an array declaration that’s longer than 80 characters, split it into a multi-line array, like below:

php
$items['advanced_forum_l'] = [
  'variables' => [
    'text' => NULL,
    'path' => NULL,
    'options' => [],
    'button_class' => NULL,
  ],
];

Here we see each item is on its own line, and each item is followed by a comma, even the last item. This is a Drupal best practice regarding arrays in PHP (other languages, such as JavaScript, may differ).

Operators

There should always be one space around operators (=, -, +, *, =>, ., etc). Whether you’re doing math, assignments, or concatenating strings - when in doubt, every piece of an expression probably needs to be separated by one space. Just one! You do not need spaces just inside of parentheses.

Here’s an example without spaces, to show how hard it is to read:

php
  if ($a='system'||$b=='system') {
    return $a=='system'?-1:1;
  }

And properly formatted:

php
  if ($a == 'system' || $b == 'system') {
    return $a == 'system' ? -1 : 1;
  }

Function Calls and declarations

When declaring a function, there should always be a single space after the argument list and before the opening curly brace. The function then begins on the next line, indented with 2 spaces. The closing brace goes on its own line.

A function call always has a set of parentheses, with no spaces on either side of them, whether or not there are parameters. If there are parameters, they should be separated by a comma, followed by a space. This update hook from the Advanced Forum contributed module is a simple example of both a function declaration and function call:

php
function advanced_forum_update_7200() {
  if (variable_get('advanced_forum_forum_disabled') == NULL) {
    variable_set('advanced_forum_forum_disabled', FALSE);
  }

Class Constructor Calls

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

php
$foo = new MyClassName();

This is to maintain consistency with constructors that have arguments:

php
$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:

php
$bar = 'MyClassName';
$foo = new $bar();
$foo = new $bar($arg1, $arg2);

String Concatenations

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

php
<?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
<?php
  $string = "Foo $bar";
?>

When using the concatenating assignment operator ('.='), use a space on each side as with the assignment operator:

php
<?php
$string .= 'Foo';
$string .= $bar;
$string .= baz();
?>

Comments

Comment standards are discussed on the separate Doxygen and comment formatting conventions page.

Twig

In Drupal, we use the Twig template engine. The Drupal Twig standards on Drupal.org updated Jan 2023 are based on the Twig coding standards, and you can learn more about them in the Twig Code Standards tutorial.

Casting

For casting, always put a space between the type and the variable, like in this snippet from the Big Menu contributed module::

php
$p_depth = 'p' . (string) ((int) $depth + 3);

Note that there is a space after (string) and after (int).

Semicolons

Every PHP statement ends with a semicolon. Always!

PHP tags

All PHP files begin with an opening tag, <?php, but never, ever use a closing tag. There are many reasons for this, one of which is that whitespace after a closing tag can cause errors, so allowing PHP to close it on its own eliminates those errors.

Also, never use PHP short tags (<? ?>).

Drupal Code Standards (Tools and Resources)

  • PHP CodeSniffer (phpcs): Use tools like PHP CodeSniffer with the Drupal coding standards to automatically check your code formatting.
  • Drupal Coder: Use the Drupal Coder module to enforce coding standards.

Example phpcs output:

joe:/var/www/html$ ./vendor/bin/phpcs
E.EE.E..EE 10 / 10 (100%)

FILE: /var/www/html/web/modules/custom/anytown/anytown.module
---------------------------------------------------------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
---------------------------------------------------------------------------------------------------------------------
 119 | ERROR | Description for the @return value is missing
     |       | (Drupal.Commenting.FunctionComment.MissingReturnComment)
---------------------------------------------------------------------------------------------------------------------

FILE: /var/www/html/web/modules/custom/anytown/src/Controller/Attending.php
---------------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
---------------------------------------------------------------------------
 9 | ERROR | Doc comment is empty (Drupal.Commenting.DocComment.Empty)
---------------------------------------------------------------------------

Questions

Check this code snippet and fix coding standards:

php
<?php
namespace Drupal\portal_int_import;
use Drupal\Core\Entity\EntityTypeManagerInterface;

class ImportService
{
  
  public function __construct(
    private EntityTypeManagerInterface $entity_type_manager,
  ) {}

  /**
   * Create user.
   */
  public function createuser(array $data){
    $user = $this->entityTypeManager->getStorage('user')->create();
    $user->enforceIsNew();

    
    
    return $user;
  }

}
Reveal the answer
php
<?php

namespace Drupal\portal_int_import;

use Drupal\Core\Entity\EntityTypeManagerInterface;

/**
 * Service to import from spreadsheet.
 */
class ImportService {

  /**
   * UserImportHelper constructor.
   */
  public function __construct(
    private EntityTypeManagerInterface $entityTypeManager,
  ) {}

  /**
   * Create user.
   *
   * @param array $data
   *   Entry data from Spreadsheet. Only normalized data should be
   *   passed here. Check $this->normalizeDataRecord().
   */
  public function createUser(array $data) {
    $user = $this->entityTypeManager->getStorage('user')->create();
    $user->enforceIsNew();

    return $user;
  }

}

Resources