Правила оформления PHP-кода

Данный документ содержит основные правила оформлени PHP-кода, принятые в компании.

Любой новый код пишется с применением этих правил.

При правках старого кода затронутые участки приводятся в соответствие с документом. Если есть возможность, исправляется весь файл. При добавлении файл в git вносится комментарий: note: code rules applied (partially).

Все предлагаемые правки и дополнения отправляются на рассмотрение в виде пулл-реквеста к данному документу.

Именование

  • Имена классов пишутся в стиле CamelCase с первой заглавной буквой

  • Имена функций, методов, свойств и переменных - camelCase с первой строчной буквой. Исключение: имена методов контроллеров CakePHP, доступных через HTTP, записываются в стиле under_score

  • Имена ключей ассоциативных массивов - under_score

  • Имена констант - UPPER_CASE

Имена приватных методов должны начинаться с двух подчеркиваний, например, __privateMethod.

Компановка кода классов

  1. Свойства фреймворка
  2. Собственные свойства
  3. HTTP-методы
  4. Публичные методы
  5. Защищенные методы
  6. Приватные методы

Базовое форматирование

Табуляция

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

Пример:

class MyClass {

  public $myVar = array(
    'item_one' => 1,
    'item_two' => 2,
  );

  public function example($arg) {
    if ($condition) {
      foreach ($arg as $i) {
        print exp($i);
      }
    }
  }
}

Пробелы

Все операторы, включая операторы конкатенации и присваивания, выделяются пробелом с обеих сторон. Исключение: оператор отрицания пробелами не выделяется.

Пример:

$string = $subString1 . $subString2;

if (!$condition) {
	$a = $b + $c - ($d / 10 * $i);
}

Разрешается выравнивать знаки "равно" в серии присваиваний пробелами по правому краю.

Пример:

$title        = 'some text';
$ordersCount  = 5;
$customers    = array ();

В списке аргументов ставятся пробелы после запятых.

Пример:

str_replace(' ', '_', $string);

При определении функции перед скобками с аргументами пробел не ставится.

Пример:

function foo($message) {

    echo $message;
}

Перенос строк

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

При объявлении массива первый и каждый последующий уровень вложенности выделяется дополнительной табуляцией (подробнее в разделе "Табуляция").

Пример

$myArray = array(
	'item_one' => 'Some string',
	'item_two' => array(
		1, 2, 3, 4, 5,
	),
	...
);

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

Пример

$value = someFunction(
	$firstVeryLongNameArgument,
	$secondVeryLongNameArgument
);

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

Пример:

$imageAspectRatio = $this->request->data['Image']['with']
	/ $this->request->data['Image']['height'];
	
if (
	$this->User->save($this->request->data)
	&& $this->request->data['User']['subscribe']
) {
	$this->Mailchimp->add_subscriber($this->request->data);
}

$name = $this->request->data['User']['first_name'] . ' '
	. $this->request->data['User']['last_name'];

В цепочке вызовов методов каждый новый вызов (кроме первого) переносится на новую строку и выделяется дополнительной табуляцией.

Пример

$report['projects_processed_in_date_range'] = $project->where('date_imported', '>=', $dateFrom)
    ->where('date_imported', '<', $dateTo)
    ->where('processed', 1)
    ->get()
    ->toArray();

Блоки кода

Фигурные скобки

Открывающая скобка ставится на одной строке с выражением, через пробел. Закрывающая - всегда на новой строке.

Пример:

if ($a == $b) {
    echo 'Hello world!';
    echo 'Goodbye!';
}

При использовании множественного условного ветвения каждое очередное условие и конечное условие else пишутся на той же строке, что и закрывающая фигурная скобка блока кода, принадлежащего предыдущему условию.

Пример:

if ($var = 'foo') {
	echo 'bar';
} elseif ($var == 'baz') {
	echo 'qux';
} else {
	echo 'Something went wrong';
}

Если фигурные скобки требуются, но выражения в них нет, то они не переносятся на новую строку (пробел внутри не ставится).

Пример:

class MyClass implements MyInterface {

	public function sum($a, $b) {

		return $a + $b;
	}
	
	public function multiplication($a, $b) {}
}

Пропуск строк

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

Если в коде подряд идут несколько закрывающих фигурных скобок дополнительное выделение пустой строкой не производится.

Пример

class MyClass {

	public $var = 'Some string';
	
	public funtion someMethod($a, $b) {

		$a = 1;
	
		if ($a > $b) {
			echo 'a more then b';
		} elseif ($a < $b) {
			echo 'b more then a';
		} else {
			echo 'a equals b';

			return false;
		}
	}
}

Рекомендуется оставлять пустую строку перед оператором return. Исключение: единственный вызов return в ветке условного оператора.

Пример:

function myFunction($paramOne, $paramTwo) {

	if ($a > $b) {
		return true;
	} elseif ($a < $b) {
		return true;
	} else {
		return false;
	}

	$instanceOne->setWidth(100);
	$instanceOne->setHeight(80);
	$instanceOne->setQuality(75);

	return true;
}

Рекомендуется разбивать пустыми строками длинные участки кода, группируя логически связанные части.

Пример:

function myFunction($paramOne, $paramTwo) {

	$insanceOne = new SomeClass($paramOne);
		
	$instanceOne->setWidth(100);
	$instanceOne->setHeight(80);
	$instanceOne->setQuality(75);
		
	$instanceTwo = new OtherClass($paramTwo);
		
	$instanceTwo->render($instanceOne);
		
	return $instanceTwo->getRresult();
}

Строки

Выбор кавычек

В простых строковых выражениях используются одинарные кавычки. При необходимости подстановки в строку значений используются двойные кавычки.

Примечание: если строка уже содержит кавычки, внешние кавычки выбираются таким образом, чтобы уменьшить число экранирующих символов.

Пример:

$stringOne = 'Some value';

$stringTwo = "Some {$value}";

Конкатенация и интерполяция

В строковых выражениях предпочтительнее использовать интреполяцию.

Конкатенация используется только в сложных случаях, содержащих циклы, логические ветвления или тернарный оператор.

Пример:

foreach ($someArray as $key => $value) {

	if (($key % 2) == 0) {
		$even .= $value;
	} else {
		$odd .= $value;
	}
}

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

Пример:

$link = '<a href="' . $href . '" class="' . $class . '">' . $name . '</a>';

Комментарии

Язык - английский.

Необходимо комментировать классы, их методы и атрибуты, функции, за исключением стандартных элементов фреймворков.

Формат комментариев phpDocumentor.

Обязательные параметры:

  • краткое описание
  • в функциях - входные параметры (@param) и возвращаемое значение (@return), если оно есть
  • если функция принимает или возвращает массив, описать его формат в расширенном описании
  • если метод может кинуть исключение, нужно описать само исключение и возможную причину в секции (@throws)
  • если метод или свойство не доступно извне, то указывается @access private
  • все свойства класса не относящиеся к фреймворку необходимо документировать (@var)
  • если метод не завершен, описать не достающую функциональность в @todo

Настоятельно рекомендуется документировать "магические" или созданные неявно сущности для нормальной работы автодополнения IDE.

Пример 1. Перечисление используемых моделей в контроллере CakePHP:

/**
 * Pages Controller
 *
 * @property Page $Page
 * @property Category $Category
 * @property Image $Image
 */
class PagesController extends AppController {
...

Пример 2. Описание переменной $this и переданной из контроллера переменной $user в шаблоне CakePHP

/**
 * @var View $this
 * @var Array $user
 */
 
$this->Form->create();