Стандарты кодирования PHP — самый главный набор требований и правил, который должны соблюдать разработчики, когда пишут код для Drupal, так как PHP является основным языком системы.
¶Отступы и пробелы
Для отступов используйте 2 пробела. Табы запрещены.
Файлы должны быть отформатированы в Unix формате. Это значит, что переход на новую строку должен быть \n
, а не \r\n
.
Все файлы с кодом и текстом должны заканчиваться пустой строкой. Это решает проблемы с "\ No newline at end of file" и позволяет легче читать патчи.
Все блоки в начале PHP файла должны быть разделены пустой линией, это также касается /** @file */
блока, объявления неймеспейсов, использование use
и весь последующий код.
Примеры правильного форматирования:
<?php
namespace This\Is\The\Namespace;
use Drupal\foo\Bar;
/**
* Provides examples.
*/
class ExampleClassName {
<?php
/**
* @file
* Provides example functionality.
*/
use Drupal\foo\Bar;
/**
* Implements hook_help().
*/
function example_help($route_name) {
¶Операторы
Все двоичные операторы (которые идут между двумя значениями), такие как +
, -
, =
, !=
, ==
, >
, и т.д., должны иметь пробел перед и после оператора, для читаемости. Например, присвоение переменной должно выглядеть как $foo = $bar;
, а не $foo=$bar;
.
Для одинарных операторов (которые управляют только одним значением), таких как ++
, пробелы не ставятся, как до, так и после.
Для сравнения преобразованных типов мы используем !=
, использование <>
запрещено.
¶Преобразование типа переменной
При преобразовании типа переменной ставится пробел между типом и самой переменной. Например (int) $foo
.
¶Управляющие конструкции
Управляющие конструкции включают в себя if
, for
, while
, switch
и т.д.
Пример if
условия со всеми возможными вариантами:
if (condition1 || condition2) {
action1;
}
elseif (condition3 && condition4) {
action2;
}
else {
defaultaction;
}
Не используйте else if
, всегда должно быть elseif
.
Управляющие конструкции должны иметь пробел между ключевым словом конструкции и открывающей скобкой, чтобы их было визуально проще отличать от вызова функий.
Всегда используйте фигурные скобки, даже тогда, когда их использование технически опционально. Они повышают читаемость кода и уменьшают вероятность логических ошибок при добавлении новых линий. Открывающая фигурная скобка всегда должна находиться на той же линии где и оператор, с пробелом перед ней. Закрывающая фигурная скобка всегда должна быть на собственной линии, и иметь тот же отступ как и открывающий оператор.
Пример switch
:
switch (condition) {
case 1:
action1;
break;
case 2:
action2;
break;
default:
defaultaction;
}
Пример do-while
:
do {
actions;
} while ($condition);
¶Длина линий и обертка
- Все линии кода не должны быть длиннее 80 символов.
- Линии содержащие названия функций длиннее данного значения, переменные, объявления и т.д., могут превышать это ограничение.
- Управляющие структуры условий могут превышать 80 символов, если их при этом остается легко читать и понимать.
Пример допустимых вариантов:
if ($something['with']['something']['else']['in']['here'] == mymodule_check_something($whatever['else'])) {
...
}
if (isset($something['what']['ever']) && $something['what']['ever'] > $infinite && user_access('galaxy')) {
...
}
// Неочевидные и сложные условия допустимы, но должны быть всегда задокументированы,
// описывая зачем та или иная проверка производится.
if (preg_match('@(/|\\)(\.\.|~)@', $target) && strpos($target_dir, $repository) !== 0) {
return FALSE;
}
- Условия не должны быть обернуты в несколько линий.
- Управляющие структуры условий также не должны пытаться выиграть Награду за самое компактное условие при меньшем числе строк кода™:
// Никогда не делайте такого!
if ((isset($key) && !empty($user->uid) && $key == $user->uid) || (isset($user->cache) ? $user->cache : '') == ip_address() || isset($value) && $value >= time())) {
...
}
Вместо этого мы рекомендуем дробить условия на самостоятельные куски, что также позволяет спокойно документировать, почему те или иные условия написаны и что они делают.
Правильный пример того что выше:
// Ключ валидный, только если он равен ID текущего пользователя, в противном
// случае, другие пользователи смогут получить доступ к любым данным.
$is_valid_user = isset($key) && !empty($user->uid) && $key == $user->uid;
// IP адрес должен равняться кешу, для предотвращения подмены сессии.
$is_valid_cache = isset($user->cache) ? $user->cache == ip_address() : FALSE;
// Альтернативно, если параметр запроса находится в будущем, то он всегда
// действителен, потому что галактика всё равно взорвется и рухнет.
$is_valid_query = $is_valid_cache || (isset($value) && $value >= time());
if ($is_valid_user || $is_valid_query) {
...
}
Данный пример по прежнему не совсем прозрачен и понятен что делает. Всегда берите во внимание и решайте, с пониманием чего могут возникнуть сложности, и объясните те конструкции подробнее.
¶Вызов функций
Функции должны вызываться без пробелов между названием функции и её открывающей скобкой и пробелом между первым аргументом. Пробелы должны быть между запятыми и следующим параметром, но пробелов не должно быть между последним параметром и закрывающей скобкой, также и до точки с запятой.
$var = foo($bar, $baz, $quux);
¶Объявление функций
function funstuff_sustem($field) {
$system['description'] = t('This module inserts funny text into posts randomly.');
return $system[$field];
}
Аргументы со значениями по умолчанию должны быть в конце списка. Если функция возвращает какие-то данные, убедитесь что они осмысленны.
Анонимные функции должны иметь пробел между function
и его скобками, как в следующем примере:
array_map(function ($item) use ($id) {
return $item[$id];
}, $items);
¶Вызов конструктора класса
Когда вызываете конструктор без аргументов, всегда добавляйте скобки:
$foo = new MyClassName();
Это позволяет соблюдать последовательность с конструкторами, имеющие аргументы:
$foo = new MyClassName($arg1, $arg2);
Если название класса является переменной, то используйте следующий пример:
$bar = 'MyClassName';
$foo = new $bar();
$foo = new $bar($arg1, $arg2);
¶Массивы
Массивы должны быть отформатированы коротким синтаксисом, значения которого разделяются пробелом после каждого элемента (запятой), а также пробелами между оператором ассоциации =>
.
$some_array = ['hello', 'world', 'foo' => 'bar'];
Если объявление массива длиннее 80 символов, то каждый элемент должен быть на своей собственной линии с увеличением вложенности на 1 уровень.
$form['title'] = [
'#type' => 'textfield',
'#title' => t('Title'),
'#size' => 60,
'#maxlength' => 128,
'#description' => t('The title of your node.'),
];
Обратите внимание на запятую в конце последнего элемента массива. Это не опечатка! Это позволяет предотвратить ошибки парсинга, если в массив будут добавлены новые элементы в дальнейшем.
¶Кавычки
Drupal не имеет жестких стандартов на счет одиночных или двойных кавычек. Где возможно, соблюдайте последовательность с модулем и уважайте стиль других разработчиков.
Имя это ввиду, одиночные кавычки должны использовать по умолчанию. Они рекомендуются для использования кроме двух случаев:
- Интерполяция переменных в строке
"<h2>$header</h2>"
. - Переводимые строки, где требуется эскейпинг данных. Например
"He's a good person."
— предпочтительный и правильный вариант'He\'s a good person.'
. Подобный эскейпинг может быть неправильно обработан генератором .pot файлов (переводов), и просто странно выглядит.
¶Объединение строк
Всегда используйте пробел между точкой и объединяемыми частями для улучшения читаемости:
$string = 'Foo' . $bar;
$string = $bar . 'foo';
$string = bar() . 'foo';
$string = 'foo' . 'bar';
Когда вы объединяете значение простой переменной, используйте двойные кавычки, вместо одинарных:
$string = "Foo $bar";
Когда используете объединение при помощи оператора .=
, используйте пробел по сторонам оператора:
$string .= 'Foo';
$string .= $bar;
$string .= baz();
¶"Включение" кода
Везде, где вы подключаете файл с кодом без условий, используйте require_once()
.
Когда подключаете код с использованием условий, используйте include_once()
. Таким образом, файл будет импортирован лишь единожды.
Когда вы внедряете код из текущей директории или подпапки, путь до файла должен начинаться с точки .
(текущая директория в файловых системах): include_once ./includes/mymodyle_formatting.inc
.
Используйте константу DRUPAL_ROOT
чтобы указать путь до файла относительно корня Drupal. Корнем является директория, где находится файл index.php. Например: require_once DRUPAL_ROOT . '/' . variable_get('cache_inc', 'includes/cache.inc');
.
Для того чтобы подгрузить код из конкретного модуля:
module_load_include('inc', 'node', 'node.admin');
¶Тэги PHP
Всегда используйте <?php ?>
для PHP кода. Не используйте краткую запись <? ?>
. Это требование Drupal, а также позволяет делать код максимально портативным, так как включение кода на PHP, на различных системах, может отличаться.
У PHP файлов, не указывайте закрывающий ?>
в конце файла. Это сделано специально:
- Удаление данного тега решает проблему с нежелательными пустыми строками в конце файла, которые приводят к ошибкам "header already sent", проблем с валидацией XHTML/XML и ряд других проблем.
- Закрывающий тег является опциональным.
- PHP.net также удаляют закрывающий тег в конце файла (например: prepend.inc), что можно расценивать как "лучшая практика".
¶Точка с запятой
В PHP точка с запятой обязательна почти во всех ситуациях, но разрешает их опускать в конце блоков кода. Drupal стандарты требуют указывать их, даже в конце блоков кода.
<?php print $tax; ?> -- Правильно
<?php print $tax ?> -- Не правильно
¶Примеры ссылок
Если вы хотите указать пример ссылки, всегда используйте домен "example.com" для таких ссылок согласно RFC 2606.
¶Соглашение об именовании
¶Функции и переменные
Названия функций должны быть в нижнем регистре, а слова разделены нижним подчеркиванием. Название функций также должны иметь группирующее название (модуля, темы) в качестве префикса, для того чтобы исключить пересечения с другими модулями.
Переменные должны быть в нижнем регистре, а слова разделены либо заглавными буквами (пример: $lowerCamelCase
), либо нижним подчеркиванием (например: $snake_case
). Будьте постоянны, не смешивайте оба варианта внутри файла.
¶Постоянные переменные
Постоянные переменные — те что установлены при помощи \Drupal::state()
, должны всегда быть в нижнем регистре, а слова разделены нижним подчеркиванием. Они также должны иметь префикс в виде модуля, для исключения пересечения с переменными других модулей.
¶Константы
- Константы всегда должны быть в верхнем регистре, с нижним подчеркиванием в качестве разделителя слов. Это правило также касается предустановленных констант в PHP, таких как
TRUE
,FALSE
иNULL
. - Константы объявленные модулем, должны иметь в качестве префикса название модуля, также в верхнем регистре.
- Начиная с Drupal 8 и выше, все константы должны быть объявлены при помощи ключевого слова
const
(подробнее), вместоdefine()
, так как это лучше для производительности.
/**
* Indicates that the item should be removed at the next general cache wipe.
*/
const CACHE_TEMPORARY = -1;
Обратите внимание что const
не работает с выражениями PHP. Используйте define()
, когда объявляете константу при определенных условиях или значениях литералов:
if (!defined('MAINTENANCE_MODE')) {
define('MAINTENANCE_MODE', 'error');
}
¶Глобальные переменные
Если вам необходимо объявить глобальную переменную, то не забудьте добавить к названию в качестве префикса название модуля, а слова разделяйте нижним подчеркиванием.
¶Название файлов
Все файлы документации должны иметь расширение ".txt", для того чтобы просмотр на Windows системах был проще. Также, название данных файлов должно быть в верхнем регистре (например README.txt, вместо readme.txt), тогда как расширение остается в нижнем.
Примеры: README.txt, INSTALL.txt, TODO.txt, CHANGELOG.txt и т.д.
¶Ссылки
- Coding standards (англ.), drupal.org