Skip to content

Latest commit

 

History

History
719 lines (578 loc) · 23.4 KB

1.generalCode.md

File metadata and controls

719 lines (578 loc) · 23.4 KB

1. Общие положения по коду (Общее для PHP и JavaScript)

Кодировка - строго 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'];
}