Стандарты 1С-Битрикс

Качество программы начинается с качества ее исходного кода. Основным фактором качества исходного кода программы является его читаемость и понятность. Необходимо формализовать правила написания кода, которые сделают чужой код читабельнее и понятнее. Правила форматирования кода должны быть едиными во всем проекте. И крайне желательно, чтобы они были очень похожими между проектами.

Форматирование кода

Длина строки

Нужно стараться избегать строк длинной более 120 символов. Если строка превышает этот размер, то нужно использовать правила переноса строки.

Правила переноса строки

Если длина строки превышает 120 символов, то необходимо пользоваться следующими правилами переноса:

  • переносить можно после запятой или перед оператором;
  • переносимая строка должна быть сдвинута относительно верхней на один символ табуляции;
  • переносы должны быть в стиле UNIX.

Пример 1 для строки:


$arAuthResult = $USER->ChangePassword($USER_LOGIN, $USER_CHECKWORD, $USER_PASSWORD, $USER_CONFIRM_PASSWORD, $USER_LID);

допустимым будет следующий вариант переноса:


$arAuthResult = $USER->ChangePassword($USER_LOGIN, $USER_CHECKWORD, $USER_PASSWORD, $USER_CONFIRM_PASSWORD, $USER_LID);

Пример 2 для строки:


if(COption::GetOptionString("main", "new_user_registration", "N")=="Y" 
&& $_SERVER['REQUEST_METHOD']=='POST' && $TYPE=="REGISTRATION" && 
(!defined("ADMIN_SECTION") || ADMIN_SECTION!==true)) 

допустимым будет следующий вариант переноса


if (COption::GetOptionString("main", "new_user_registration", "N") == "Y"
     && $_SERVER['REQUEST_METHOD'] == 'POST' && $TYPE == "REGISTRATION"
     && (!defined("ADMIN_SECTION") || ADMIN_SECTION !== true))

Пробелы и табуляция

Для форматирования отступов в коде нужно использовать табуляцию. Использование пробелов запрещено. Причины:

  • в случае использования табуляции каждый может настроить в своем редакторе желаемый отступ;
  • используется один символ вместо нескольких;
  • в случае смешивания пробелов и табуляции текст будет прыгать, разрушая форматирование.

Форматирование подчиненности

Подчиненный код должен быть сдвинут от главного ровно на один символ табуляции. Подчиненный код не может находиться на той же строке, что и главный. Отступ более чем пятого уровня может служить указанием, что код стоит вынести в отдельный блок. Пример:


function func()
{
     if (condition)
     {
          while (condition2)
          {

          }
      }
}

Правила расстановки фигурных скобок

Открывающая скобка должна ставится под соответствующим оператором и на одном отступе с ним. Закрывающая скобка должна ставится под соответствующей открывающей. Пример:


if ($condition)
{
   ...
}

Использование тернарного оператора "?:"

Условие следует заключать в скобки, тем самым отделяя его от остального кода. По возможности, действия, производимые по условию, должны быть простыми функциями. Если весь блок ветвления плохо читается, то стоит заменить его на if/else.

Пример: (условие ? funct1() : func2());

Инструкция, выражения

Выражения

Желательно, чтобы в каждой строчке присутствовало только одно выражение

Пример.
Неправильно писать так:


$a = $b; $b = $c; $c = $a;

Правильно писать так:


$a = $b;
$b = $c;
$c = $a;

Инструкции "if", "else", "while" и т.п.

При написании инструкций должно строго применяться правило Форматирование подчиненности: тело инструкции должно быть сдвинуто на один символ табуляции вправо от самой инструкции. Фигурные скобки должны использоваться всегда, находиться на отдельных строках, на одном уровне с инструкцией.

Пример. Неправильно писать так:


$a = $b;
$b = $c;
$c = $a;

Правильно писать так:


if ($a == 0)
{
  $a = 10;
}
else
{
  $a = 5;
  $b = 10;
}

Сложные инструкции

Сложные инструкции следует разбивать по строкам. Например:


if(COption::GetOptionString("main", "new_user_registration", "N")=="Y" && $_SERVER['REQUEST_METHOD']=='POST' &&
     $TYPE=="REGISTRATION" && (!defined("ADMIN_SECTION") || ADMIN_SECTION!==true))

Можно записать как:


if (COption::GetOptionString("main", "new_user_registration", "N") == "Y"
     && $_SERVER['REQUEST_METHOD'] == 'POST' && $TYPE == "REGISTRATION"
     && (!defined("ADMIN_SECTION") || ADMIN_SECTION !== true))
{

Очень сложные инструкции рекомендуется разбивать на несколько более простых. Например:


if((!(defined("STATISTIC_ONLY") && STATISTIC_ONLY && substr($APPLICATION->GetCurPage(), 0,
     strlen(BX_ROOT."/admin/"))!=BX_ROOT."/admin/")) && COption::GetOptionString("main", "include_charset", "Y")=="Y"
     && strlen(LANG_CHARSET)>0)

Можно записать так:


$publicStatisticOnly = False;
if (defined("STATISTIC_ONLY")
  && STATISTIC_ONLY
  && substr($APPLICATION->GetCurPage(), 0, strlen(BX_ROOT."/admin/")) != BX_ROOT."/admin/")
{
     $publicStatisticOnly = True;
}
if (!$publicStatisticOnly && strlen(LANG_CHARSET) > 0
     && COption::GetOptionString("main", "include_charset", "Y") == "Y")
{

или так:


if (!defined("STATISTIC_ONLY") || ! STATISTIC_ONLY
  || substr($APPLICATION->GetCurPage(), 0, strlen(BX_ROOT."/admin/")) == BX_ROOT."/admin/")
{
  if (strlen(LANG_CHARSET) > 0 && COption::GetOptionString("main", "include_charset", "Y") == "Y")
  {
  }
}

Форматирование массивов

Массивы, которые записываются в несколько строк, следует форматировать следующим образом:


$arFilter = array(
  "key1" => "value1",
  "key2" => array(
      "key21" => "value21",
      "key22" => "value22",
  )
); 

Пустые строки и пробелы

Пустые строки помогают разбивать код приложения на логические сегменты. Несколькими строками могут отделяться секции в исходном файле. Одной пустой строкой отделяются друг от друга методы и логические секции внутри метода для более удобного чтения. Перед логической секцией рекомендуется вставить комментарий, в котором будет указано назначение этой секции (см. пункт 3).

Пробелы

После запятой должен быть пробел. После точки с запятой, если она не последняя в строке (например, в инструкции for), должен быть пробел. Перед запятой или точкой с запятой пробелы не ставятся. Все операторы должны быть отделены пробелом от операндов с обеих сторон. Замена пробела символом табуляции не допускается. Пояснения:

  • Один пробел используется в объявлении методов после запятой, но не перед скобками: TestMethod($a, $b, $c); Примеры неправильного использования:
    • TestMethod($a,$b,$c);
    • TestMethod( $a, $b, $c );
  • Так же одиночный пробел используют для выделения операторов: $a = $b * $c / $d; Пример неправильного использования: $a=$b*$c/$d;
  • Также пробелы используются при форматировании циклов: for ($i = 0; $i < 10; $i++) Пример неправильного использования: for ($i=0;$i< 10;$i++)
  • Табуляция всегда используется для отступов, но никогда не используется вместо пробелов. Пример неправильного форматирования (символ табуляции обозначен стрелкой):

            $arArray = array(
            "key1" =>→"value1",
            "key2" =>→"value2",
            );

Прочее

В сложных выражениях рекомендуется группировать операции с помощью скобок вне зависимости от того, требует это приоритет операций или нет.

Пример: $r = $a + ($b * $c);

Соглашение об именовании

Общие понятия

Не используйте подчеркивание для отделения слов внутри идентификаторов, это удлиняет идентификаторы и затрудняет чтение. Старайтесь давать переменным, методам и пр. "говорящие" названия. Предпочтительно использовать имена, которые ясно и четко описывают предназначение и/или смысл сущности. Старайтесь делать имена идентификаторов как можно короче (но не в ущерб читабельности). Если в имени содержится аббревиатура, лучше вместо всех заглавных оставить только первую букву заглавной, а остальные написать строчными. Т.е. лучше задать имя getHtmlStatistic, а не getHTMLStatistic.

Именование переменных

Первое логическое слово должно начинаться с маленькой буквы, остальные логические слова - с большой. Имена переменных могут иметь префиксы, если требуется явно указать тип переменной: ar - для массивов, db - для наборов данных из базы и т.п. Пример: $testCounter, $userPassword

Именование методов

  • Очевидность из названия действия, которое будет совершать функция\метод.
  • Использование префиксов: is (обозначение вопроса), get (получить значение), set (установить значение).

Пример: isFileWriteable()

Именование классов

  • В имени должна обозначаться сущность, описываемая классом.
  • В имени должно быть не более трех слов.
  • Нельзя использовать знак подчеркивания ('_').
  • В качестве разделителей слов в имени следует использовать заглавные буквы, строчные - для остальной части.

Пример: class SaleAffiliateAccount

Комментарии

Комментарий должны быть на английском языке и носить содержательный характер.

PHPDoc

Необходимо описывать в стиле PHPDoc все классы и их публичные методы. Пример:


/**
 * Gets a value that indicates whether a directory exists in the file system
 *
 * @param string $path - Path to the directory
 * @return bool - True if the directory exists, false - otherwise
 */

Другое

Магические числа

В коде не должно быть магических чисел. Пример плохого кода: $task->Update($taskId, array('STATUS' => 3), 1);

Пример хорошего кода: $task->Update($taskId, array('STATUS' => CTaskStatus::New), TASK_PERMISSIONS_WRITE);

Инструменты автоматического форматирования

php_beautifier

    Установить пакет php_beautifier (ubuntu):

  • sudo aptitude install php_beautifier или sudo aptitude install php-pear и sudo pear install PHP_Beautifier-0.1.15
  • cd
  • hg clone https://bitbucket.org/qMBQx8GH/bitrix_php_beautifier
  • sudo ln -s Bitrix_php_beautifier/Bitrix.filter.php /usr/share/php/PHP/Beautifier/Filter/Bitrix.filter.php

  • Настроить редактор:

  • Выбрать пункт меню Settings - Configure Kate...
  • Выбрать пункт настроек Plugins и отметить галочку рядом с Text Filter
  • Нажать OK
  • Теперь в меню Tools появился пункт Filter Text

  • Использование:

  • Выделяем строки (или Ctrl-A для всего текста)
  • Tools - Filter Text
  • Вводим (или выбираем из истории): php_beautifier -t -f - -l 'Lowercase Bitrix'
  • Нажимаем OK.