Кодировка - строго UTF-8 без BOM
Обоснование: BOM не является обязательным для кодировки utf-8 и, по сути, не несет для нее смысловой нагрузки. Более того, для php файлов, BOM отправляется браузеру, что усложняет отправку заголовков
====
Перенос строки - строго Unix-style (LF)
Обоснование: уменьшение размера файла, один символ вместо 2-х в Windows. Также, для автоматизации процесса в Windows рекомендуется почитать про git config core.autocrlf. Рекомендуется устанавливать в true и забывать о переносах строки.
====
Не рекомендуется писать строки больше 120-ти символов в длинну. Длинные конструкции рекомендуется разбивать на несколько строк с надлежащим форматированием.
Идентация кода строго обязательна. Это означает: любой блок (несколько команд, следующих одна за другой) должен быть индентирован на одинаковую глубину. Глубина вложенного блока отличается от родительского ровно на один уровень.
ПЛОХО: (Индентация отсутствует либо нелогична)
class SomeClass {
private $foo;
public $bar;
public function process () {
$a = 0;
$b = 1;
$this->foo = $this->bar;
}
}
ПЛОХО: (вложенный блок индентируется на два уровня больше, чем родительский)
if ($user->isJedi()) {
GlobalForce::setForceDisturbance($user);
}
ХОРОШО:
class SomeClass {
private $foo;
public $bar;
public function process () {
$a = 0;
$b = 1;
$this->foo = $this->bar;
}
}
ХОРОШО:
if ($user->isJedi()) {
GlobalForce::setForceDisturbance($user);
}
====
Отступ для индентации кода - строго табулятор (Tab). (Некоторые интерпретаторы данного документа могут отображать Tab-ы пробелами) См. Lea Verou: Why tabs are clearly superior
Обоснование: т. к. Tab vs Spaces - очень жаркий и неутихающий годами холивар со множеством аргументов за и против у каждой из сторон, было принято волевое решение: стукнуть кулаком по столу и "устаканить" символы для индентации раз и навсегда.
====
Запрещено использовать Tab для "выравнивания" кода:
ПЛОХО: (Используются Tab-ы перед символами "=")
private $text = 'abracadabra';
private $other_texts = 'arbadacarba';
ХОРОШО: (Используются пробелы)
private $text = 'abracadabra';
private $other_texts = 'arbadacarba';
Обоснование: код будет "выравнен" вне зависимости от размера таба
====
При чейнинге методов рекомендуется сносить методы на следующую строку с индентацией на один уровень. Рекомендация становится необходимостью, если методов больше двух. При этом разрешается оставлять фильтрующую функцию на первой строке, если она одна.
ПЛОХО:
$container.find('.js-something').show().removeClass('.js-disabled').data('someDataKey',someDataHere);
ХОРОШО:
$container.find('.js-something')
.show()
.removeClass('.js-disabled')
.data('someDataKey', someDataHere);
Все константы должны записываться в верхнем регистре, смысловые слова разделяются символами подчеркивания
ПЛОХО:
define('maximum_punches_in_face',1000);
class SomeClass {
const maximum = 1000;
}
ХОРОШО:
define('MAXIMUM_PUNCHES_IN_FACE',1000);
class SomeClass {
const MAXIMUM = 1000;
}
Обоснование: константы в коде "бросаются в глаза" и легко отличимы от переменных
====
Булевы и специальные типы данных записываются либо в вехнем либо в нижнем регистре. Запрещается смешивать регистры. Рекомендуется нижний регистр.
Это правило применяется к ключевым словам: true
, false
, null
, undefined
.
ПЛОХО:
$isOK = False;
ЕЩЕ ХУЖЕ:
$isOK = FaLsE;
ХОРОШО:
$isOK = false;
$hasChildren = FALSE;
Язык названий переменных/классов/функций и т. д. - строго английский.
ПЛОХО:
var PeriodoEntrePulsaciones = 300;
var taimautNaAyaksZapros = 300;
ХОРОШО:
var requestTimeout = 300;
====
Любое имя должно быть лаконичным, но понятным: имя должно описывать назначение переменной/функции/класса, чем короче это описание, тем лучше. Общее правило именования: класс и переменная - имя существительное, функция и метод - глагол.
ПЛОХО:
var bnum = fv + bc,
someAwesomeNumberThatMakesEverythingAwesome = 0,
iterate = 0;
magic();
ХОРОШО:
var resultBlocksCount = fieldValue + baseCount,
awesomeNumber = 0,
iterationsCount = 0;
doMagic();
====
Имена классов и объектов-контроллеров (в JavaScript) строго PascalCase (UpperCamelCase), разрешено использование нижней черты (_
) в php и только там (autoloader может ориентироваться на этот символ для поиска требуемого класса в файлах проекта).
ПЛОХО:
var some_page_controlling_object = { /* snip */ };
var Some_Page_Controller_Object = { /* snip */ };
var somepagecontrollerobject = { /* snip */ };
ХОРОШО:
var SomePageControllerObject = { /* snip */ };
class AdminCore_SystemLanguages_AdminController { /* snip */ }
====
Имена функций и переменных - строго CamelCase (lowerCamelCase). Единственным исключением является случай, когда первое слово - аббревиатура
ПЛОХО:
function do_something_awesome () { /* snip */ }
var XML_text = '';
ХОРОШО:
function doSomethingAwesome () { /* snip */ }
var XMLText = '';
====
Имена геттеров и сеттеров обязаны начинаться с get
и set
соответственно
ПЛОХО:
public function id() { return $this->id; }
public function retrieveName() { return $this->name; }
ХОРОШО:
public function getId() { return $this->id; }
public function getName() { return $this->name; }
====
Односимвольные имена переменных запрещены. Единственным исключением являеется случай, когда переменная является итератором цикла
ПЛОХО:
$t = time();
ХОРОШО:
for ($i = 0, $c = count($elements); $i < c; $i++) { /* snip */ }
В логических, строковых и арифметических операциях, а также во время группировки скобками и присваивания, обязательно использование пробелов слева и справа от операндов. Исключения:
- Для логического отрицания отступ справа запрещен
- Конкатенацию не рекомендуется выделять пробелами
- Разрешается не использовать внутренние боковые отступы внутри скобок
ПЛОХО:
// Нет отступов у присваивания и символа +
$x=1+4;
// Нет отступов у скобки
$y = ($x * 3)+ 2;
// Лишний отступ у !
$z = ! $lambda;
ХОРОШО:
$x = 1 + 4;
$y = ($x * 3) + 2;
$z = !$lambda;
====
Форматирование конструкции switch
должно подчиняться следующим правилам:
case
должно быть сдвинуто на один уровень относительноswitch
- код между
case
иbreak
должен быть сдвинут на один уровень относительноcase
break
настоятельно рекомендуется сдвигать на один уровень относительноcase
ПЛОХО:
switch (forcePower) {
case 'weak':
itemModifier = '_whimsyweak';
break;
case 'normal':
itemModifier = '_normal';
break;
case 'strong':
itemModifier = '_superstrong';
break;
default:
itemModifier = '_none';
break;
}
ХОРОШО:
switch (forcePower) {
case 'weak':
itemModifier = '_whimsyweak';
break;
case 'normal':
itemModifier = '_normal';
break;
case 'strong':
itemModifier = '_superstrong';
break;
default:
itemModifier = '_none';
break;
}
====
Обязательно использование пробелов при определении функций, методов, классов и в управляющих конструкциях типа for
, foreach
, if
, switch
, catch
и так далее.
Тем не менее, не рекомендуется использовать пробелы в таких случаях:
- перед запятой при перечислении аргументов функции/метода
- после открывающей и перед закрывающей скобкой списка аргументов функции/метода
- после открывающей и перед закрывающей скобкой логического условия конструкции
if
- после открывающей и перед закрывающей скобкой списка аргументов конструкций
for
,foreach
,switch
,catch
и так далее
ПЛОХО:
function makeMyDay($a,$b,$c){
$return = 0;
for($i = 1;$i < count($a);$i++){
$return += $a[$i] * ($b + $c);
}
return $return;
}
class myDayMaker{
public function checkMyDay($day){
if($day){
switch($day){
case'today':
case'tomorrow':
return 1;
break;
default:
return 0;
break;
}
}
return -1;
}
}
ХОРОШО:
function makeMyDay ($a, $b, $c){
$return = 0;
for ($i = 1; $i < count($a); $i++) {
$return += $a[$i] * ($b + $c);
}
return $return;
}
class myDayMaker {
public function checkMyDay ($day) {
if ($day) {
switch ($day) {
case 'today':
case 'tomorrow':
return 1;
break;
default:
return 0;
break;
}
}
return -1;
}
}
====
Должны использоваться "египетские скобки" (Стиль «K&R»).
====
Если скобки можно опустить, они должны быть.
ПЛОХО:
if (Luke.usesForce()) DeathStar.explode();
if (Luke.usesForce())
DeathStar.explode();
ХОРОШО:
if (Luke.usesForce()) {
DeathStar.explode();
}
Обоснование: можно будет легко добавить еще одну строку в блок, не думая о том, что надо добавить еще скобки. Также, это повышает читаемость кода.
====
В if ... else
конструкциях, else
должно быть на отдельной строке, else
на одной строке с закрывающей фигурной скобкой запрещено
ПЛОХО:
if (items.length > 0)
{
items.push(getNewItem());
}else populateItems();
ХОРОШО:
if (items.length > 0) {
items.push(getNewItem());
}
else {
populateItems();
}
====
Допускается "сворачивание" простейших геттеров/сеттеров в одну строку.
ПЛОХО:
// Too much code is "hidden"
public function getChildren () { if ($this->hasChildren()) { return $this->children; } return array(); }
ХОРОШО:
public function getChildren () { return $this->children; }
====
Запрещено использование логических операторов в символьном виде
ПЛОХО:
{if $object->hasChildren() or $forceChildrenDisplay}
ХОРОШО:
{if $object->hasChildren() || $forceChildrenDisplay}
====
Сложные (более чем на 2 оператора) логические конструкции должны быть отформатированы
ПЛОХО:
if ($isOK && ($user->isPriveleged() || $user->isRoot()) && count($result) > 0) {
/* snip */
}
ХОРОШО:
if (
$isOK &&
(
$user->isPriveleged() ||
$user->isRoot()
) &&
count($result) > 0
) {
/* snip */
}
====
Запрещено начинать строку с логического оператора при форматировании сложных логических условий
ПЛОХО:
if (
$isOK
&& $user->isRoot()
&& count($result) > 0
&& count($categories) > 1
) {
/* snip */
}
ХОРОШО:
if (
$isOK &&
$user->isRoot() &&
count($result) > 0 &&
count($categories) > 1
) {
/* snip */
}
====
Запрещено использование присваивания в логических выражениях
ПЛОХО:
if ($arrCount = count($array)) {
/* snip */
}
ХОРОШО:
$arrCount = count($array);
if ($arrCount) {
/* snip */
}
====
При инициализации ассоциативных массивов в PHP и объектов (Object
) в JavaScript каждый элемент должен располагаться на отдельной строке.
Разрешается не применять это правило если массив/объект состоит из одного элемента и конструкция легкочитаема
Для линейных массивов (и просто массивов в JavaScript) разрешается указывать элементы в одну строку и/или разбивать их на несколько строк, больше чем по элементу на строку.
Также, настоятельно рекомендуется выравнивать значения в массиве/объекте для повышения читаемости
ПЛОХО:
$basicData = array('name' => null, 'age' => 0, 'root_priveleges' => false);
$element.someJQueryPlugin({some:'initialization',parameters:'here'});
ХОРОШО:
$basicData = array(
'name' => null,
'age' => 0,
'root_priveleges' => false
);
$element.someJQueryPlugin({
some : 'initialization',
parameters : 'here'
});
// Так тоже можно, но только аккуратно
$element.someJQueryPlugin({some: 'initialization'});
====
Yoda conditions рекомендуются к применению:
if ('use' == $the_force) {
$victorious = You::will($be);
}
Обоснование: Исключается вероятность случайного присваивания
====
Рекомендуется вызовы функций с несколькими аргументами форматировать таким образом:
- Каждый аргумент располагается на своей строке
- Каждый аргумент индентирован на 1 уровень относительно уровня вызова функции
- Запятая ставится после аргумента и является последним символом в строке
- Открывающая скобка находится на одной строке с вызовом функции
- Закрывающая скобка находится на отдельной строке
ПЛОХО:
someFunction($with,$a,$hella,$lot,$ofPossiblyLong,$argumentsNamesAndStuff);
ХОРОШО:
someFunction(
$with,
$a,
$hella,
$lot,
$ofPossiblyLong,
$argumentsNamesAndStuff
);
Не рекомендуется использовать "магические числа". Если же их приходится использовать - обязателен комментарий, что это за число и почему оно используется.
ПЛОХО:
if ($items.length > 6) {
return;
}
ХОРОШО:
// Now it's magic but later it could be passed here as a user-configured value
var maxItems = 6;
/* snip */
if ($items.length > maxItems) {
return;
}
====
Строки настоятельно рекомендуется записывать в одинарных кавычках.
Обоснование: PHP ищет переменные в строках в двойных кавычках, что есть медленно и использовать не рекомендуется. Строки следует записывать в одинарных кавычках. На JavaScript это правило распространяется ради единообразия кода.
====
Обязательно использование конкатенации для записи длинных строк
ПЛОХО:
var error = 'This is a soopah long error \
that my soopah cool script trows on every occasion \
because I\'m a soopah cool web developer and \
I know how to do cool stuff';
ХОРОШО:
var error = 'This is a soopah long error '+
'that my soopah cool script trows on every occasion '+
'because I\'m a soopah cool web developer and '+
'I know how to do cool stuff';
Обоснование: без конкатенации в строки лезет "мусор" (символы, используемые для индентации), который а. не нужен, б. увеличивает объем занимаемой памяти.
====
Не полагайтесь на приведение типов: не рекомендуется пользоваться конструкциями вида
if ($possiblyEmptyArray) { /* snip */ }
если переменная не заведомо скалярна для PHP или примитивна для JavaScript.
====
Рекоменуется отделять смысловые блоки кода одной пустой строкой, желательно - с комментарием. ПЛОХО:
if (self::$dumpEnabled) {
$dumpelement['Time'] = (microtime(true) - $dumpelement['Time'])*1000;
$dumpelement['Keys'] = count(self::$text[$language][$segment]['keys']);
self::$dump[] = $dumpelement;
self::$dumpSummary['Segments']++;
self::$dumpSummary['Keys'] += $dumpelement['Keys'];
self::$dumpSummary['Time'] += $dumpelement['Time'];
}
ХОРОШО:
if (self::$dumpEnabled) {
// Preparing dump element
$dumpelement['Time'] = (microtime(true) - $dumpelement['Time'])*1000;
$dumpelement['Keys'] = count(self::$text[$language][$segment]['keys']);
// Adding dump element to dump
self::$dump[] = $dumpelement;
// Updating dump summary
self::$dumpSummary['Segments']++;
self::$dumpSummary['Keys'] += $dumpelement['Keys'];
self::$dumpSummary['Time'] += $dumpelement['Time'];
}
====
Запрещено "отделять" блоки кода друг от друга более чем двумя пустыми строками.
if (self::$dumpEnabled) {
$dumpelement['Time'] = (microtime(true) - $dumpelement['Time'])*1000;
$dumpelement['Keys'] = count(self::$text[$language][$segment]['keys']);
self::$dump[] = $dumpelement;
self::$dumpSummary['Segments']++;
self::$dumpSummary['Keys'] += $dumpelement['Keys'];
self::$dumpSummary['Time'] += $dumpelement['Time'];
}
ХОРОШО:
if (self::$dumpEnabled) {
// Preparing dump element
$dumpelement['Time'] = (microtime(true) - $dumpelement['Time'])*1000;
$dumpelement['Keys'] = count(self::$text[$language][$segment]['keys']);
// Adding dump element to dump
self::$dump[] = $dumpelement;
// Updating dump summary
self::$dumpSummary['Segments']++;
self::$dumpSummary['Keys'] += $dumpelement['Keys'];
self::$dumpSummary['Time'] += $dumpelement['Time'];
}