organized legos

Drupal Code Standards: Formatting

This is the third post in a series about Drupal coding standards. In this post we’ll talk specifically about standards regarding formatting. This is by no means an exhaustive list of PHP syntax rules, but rather is focused on formatting standards for Drupal.

Other posts in this series:

  1. Drupal Code Standards: What Are They?
  2. Drupal Code Standards: How Do We Implement Them?
  3. Drupal Code Standards: Formatting
  4. Drupal Code Standards: Documentation
  5. Drupal Code Standards: The t() function
  6. Drupal Code Standards: Object Oriented Coding & Drupal 8
  7. Drupal Code Standards: Twig in Drupal 8

Indentation

There is much debate over tabs vs spaces in the programming world, but here in the Drupal community, we use spaces. Two spaces, to be exact.

 A scene from Silicon Valley where Richard breaks up with Winnie because she uses spaces and he is a tab evangelist.

In our previous post, we talked about setting up your editor to help you out - you can set it to use 2 spaces for indentation. This is really easy in Sublime Text:

Setting indentation in Sublime Text

Whitespace

No trailing whitespace! There should never be a space at the end of a line. In our previous post, we talked about how you can set up your text editor to remove this for you automatically. Try to avoid extra blank lines throughout your files and functions. Use blank lines sparingly to keep crowded code readable, if necessary.

File endings

Unix file endings - 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.

Setting file endings in Sublime Text

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. This is easy in Sublime Text:

Setting a ruler in Sublime Text

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

  $items['advanced_forum_l'] = array(
    'variables' => array(
      'text' => NULL,
      'path' => NULL,
      'options' => array(),
      '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 Drupal best practice regarding arrays in PHP (other languages, such as Javascript, may differ).

While we’re on the subject of arrays - if you have a super long array (hundreds of items, for example), you could break each item into its own line. That would be very long, but very readable. However, if the programmer who looks at this code next is unlikely to need this information at their fingertips (for example, a list of countries or zip codes that the programmer will not need to reference), consider importing it from a csv file or similar, and keeping it out of your code.

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:

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

And properly formatted:

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

Function Calls & 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 contrib module is a simple example of both a function declaration and function call:

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

Constants

Take a look the code above - notice the all caps? TRUE, FALSE, and NULL are always capitalized in Drupal code. They are constants, which are always in all caps in Drupal.

Custom constants must be prefixed with the module name. Here’s an example from the CKEditor module:

define('CKEDITOR_FORCE_SIMPLE_TOOLBAR_NAME', 'DrupalBasic');
define('CKEDITOR_ENTERMODE_P', 1);
define('CKEDITOR_ENTERMODE_BR', 2);
define('CKEDITOR_ENTERMODE_DIV', 3);

Control Structures

When using control structures like if, else, elseif, case, switch, foreach, while, do, etc., there should always be a space after the control structure term. Also, there should always be a space before the opening curly brace. The statement is indented on the next line, and the closing brace is on its own line, much like functions.

Inline control structures are not permitted in Drupal, although they are valid PHP. You should not use either of the following structures in Drupal:

if($foo) echo bar();

Or

if($foo)
  echo bar();

Control structures must always have braces, and the statement(s) must always be on the next line:

if ($foo) {
  echo bar();
}

Here’s an example using if and foreach from the Advagg contrib module:

// Loop through all files.
 foreach ($files as $values) {
   // Insert files into the advagg_files table if it doesn't exist.
   // Update if needed.
   if (advagg_insert_update_files($values['files'], $type)) {
     $write_done = TRUE;
   }

   // Insert aggregate into the advagg_aggregates table if it doesn't exist.
   if (advagg_insert_aggregate($values['files'], $values['aggregate_filenames_hash'])) {
     $write_done = TRUE;
   }

   // Insert aggregate version information into advagg_aggregates_versions.
   if (advagg_insert_aggregate_version($values['aggregate_filenames_hash'], $values['aggregate_contents_hash'], $root)) {
     $write_done = TRUE;
   }
 }
 return $write_done;

Here’s another example with statements using if, elseif, and else. Note that in Drupal, the standard is to use elseif as one word, not else if. Both are valid PHP, but the Drupal standards specify it as one word.

if ($type === 'css') {
  list($contents) = advagg_get_css_aggregate_contents($file_aggregate, $aggregate_settings);
}
elseif ($type === 'js') {
  list($contents) = advagg_get_js_aggregate_contents($file_aggregate, $aggregate_settings);
}
if (!empty($contents)) {
  $compressed = gzencode($contents, 9, FORCE_GZIP);
  $files[$type][$filename] = strlen($compressed);
}
else {
 $files[$type][$filename] = 0;
}

Here’s an example from the Advanced Forum contrib module showing how to format a switch statement. Every case-breaking statement must be followed by a blank line. A case-breaking statement is the last statement that is executed, generally a break or return. If you take a look at the last line of the following example, you’ll see that a closing brace counts as a blank line. This is also a good example of spacing between operators.

switch ($period) {
  case 'day':
    $period_arg = 60 * 60 * 24;
    break;

  case 'week':
    $period_arg = 60 * 60 * 24 * 7;
    break;

  case 'month':
    $period_arg = 60 * 60 * 24 * 30;
    break;

  case 'quarter':
    $period_arg = 60 * 60 * 24 * 91;
      break;

  case 'year':
    $period_arg = 60 * 60 * 24 * 365;
      break;
  }

Alternate control statement syntax for theme templates

For ease of coding and readability, there is an alternate structure to use for control structures inside of theme templates in Drupal 7. Use if (): and endif; instead of braces. Statements must still be on their own line, as must the endif statement. Here’s an example from the Zen subtheme:

<?php if ($comments && $node->type != 'forum'): ?>
    <h2 class="comments__title title"><?php print t('Comments'); ?></h2>
<?php endif; ?>

Twig

In Drupal 8, we use the Twig template engine. The Drupal Twig standards can be found here, and are based on the Twig coding standards. We’ll go into more detail in a later post!

Casting

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

$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 (<? ?>).

This is a pretty solid overview of the major things that Drupal may do differently than other PHP frameworks or content management systems. If you want to dig into Drupal and PHP syntax, there’s a long rabbit hole waiting for you, but these basics will keep you from making major mistakes, and keep your code readable! You’ll also run into less hiccups when contributing to core code or modules on Drupal.org! Many of these examples were from Drupal 7 - to find out more about Drupal 8 and object-oriented programming, check back for a future blog post in this series!

We hope you learned a lot - if you learned anything new, or want to school us, reach out to us on twitter - @ChromaticHQ

Our next post will cover documentation, which is always important - in Drupal or anywhere else, so stay tuned!

Hero Photo Attribution: Windell Oskay CC

Code Standards Drupal Drupal 7 Drupal 8 PHP
Alanna Burke Headshot

Alanna's love of content management systems started with Wordpress while working at Temple University, and continued with Drupal at Saint Joseph’s University, then on to Chromatic.