Стандарт кодирования

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

Стандарт кодирования Nette соответствует PSR-12 Extended Coding Style с двумя главными исключениями: для отступов он использует табуляции вместо пробелов и PascalCase для констант классов.

Многие из этих правил умеет автоматически проверять и исправлять инструмент Nette Coding Standard, так что проверять их вручную вам не придётся.

Общие правила

  • Каждый PHP-файл должен содержать declare(strict_types=1)
  • Для разделения методов ради лучшей читаемости используются две пустые строки
  • Причина использования оператора подавления (@) должна быть задокументирована: @mkdir($dir); // @ - directory may exist
  • Если используется оператор нестрогого сравнения (то есть ==, !=, …), намерение должно быть задокументировано: // == to accept null
  • Несколько классов исключений можно записать в один файл с именем exceptions.php, а несколько перечислений – в enums.php
  • У интерфейсов видимость методов не указывается, потому что они всегда публичные
  • У каждого свойства, возвращаемого значения и параметра должен быть указан тип. И наоборот, у финальных констант тип мы никогда не указываем, потому что он очевиден
  • Для ограничения строк следует использовать одинарные кавычки, кроме случаев, когда сам литерал содержит апострофы

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

Переносы и скобки

Стандарт кодирования Nette соответствует PSR-12 (или PER Coding Style), но в некоторых пунктах уточняет или меняет его:

  • Стрелочные функции пишутся без пробела перед скобкой, то есть fn($a) => $b
  • Пустая строка между разными видами импортов use не требуется
  • Возвращаемый тип функции или метода и открывающая фигурная скобка всегда находятся на разных строках:
	public function find(
		string $dir,
		array $options,
	): array
	{
		// тело метода
	}

Открывающая фигурная скобка на отдельной строке важна для визуального отделения сигнатуры функции или метода от тела. Если сигнатура на одной строке, разделение очевидно (изображение слева). Если она на нескольких строках, в PSR сигнатура и тело сливаются (посередине), а в стандарте Nette остаются разделёнными (справа):

Блоки документации (phpDoc)

Главное правило: никогда не дублируйте сведения из сигнатуры, такие как тип параметра или возвращаемый тип, если это не добавляет ценности.

Блок документации к определению класса:

  • Начинается с описания класса
  • Дальше пустая строка
  • Дальше аннотации @property (или @property-read, @property-write), по одной на строку. Синтаксис: аннотация, пробел, тип, пробел, $имя
  • Дальше аннотации @method, по одной на строку. Синтаксис: аннотация, пробел, возвращаемый тип, пробел, имя(тип $параметр, ...)
  • Аннотация @author опускается. Авторство хранится в истории исходного кода
  • Можно использовать аннотации @internal или @deprecated
/**
 * MIME message part.
 *
 * @property string $encoding
 * @property-read array $headers
 * @method string getSomething(string $name)
 * @method static bool isEnabled()
 */

Блок документации к свойству, содержащий только аннотацию @var, должен быть на одной строке:

/** @var string[] */
private array $name;

Блок документации к определению метода:

  • Начинается с краткого описания метода
  • Без пустой строки
  • Аннотации @param, по одной на строку
  • Аннотация @return
  • Аннотации @throws, по одной на строку
  • Можно использовать аннотации @internal или @deprecated

За каждой аннотацией следует один пробел, кроме @param, за которой ради лучшей читаемости следуют два пробела.

/**
 * Finds a file in directory.
 * @param  string[]  $options
 * @return string[]
 * @throws DirectoryNotFoundException
 */
public function find(string $dir, array $options): array

Глобальные функции и константы

Глобальные функции и константы пишутся без ведущего обратного слеша, то есть count($arr), а не \count($arr). Для функций, которые PHP умеет оптимизировать, добавьте в начало файла use function, чтобы компилятор мог перевести их эффективнее. К ним относятся функции вроде count, strlen, is_array, is_string, is_scalar, sprintf и т. п. Функции перечисляются на одной строке, чтобы блок импортов оставался компактным:

use Nette;
use function count, is_array, is_scalar, sprintf;

Изредка мы импортируем и константы, знание значения которых может помочь компилятору:

use const PHP_OS_FAMILY;

Табуляции вместо пробелов

У табуляций есть несколько преимуществ перед пробелами:

  • Размер отступа настраивается в редакторах и в вебе
  • Они не навязывают коду предпочтения автора по размеру отступа, благодаря чему код становится переносимее
  • Их можно ввести одним нажатием клавиши (где угодно, а не только в редакторах, которые преобразуют табуляции в пробелы)
  • Отступ – их прямое назначение
  • Они учитывают нужды слабовидящих и слепых коллег

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

Для слепых программистов, использующих брайлевские дисплеи, каждый пробел означает одну брайлевскую ячейку. Так что если отступ по умолчанию равен 4 пробелам, отступ 3-го уровня тратит 12 ценных брайлевских ячеек ещё до начала кода. На дисплее из 40 ячеек, самом распространённом для ноутбуков, это больше четверти доступных ячеек, потраченных впустую и не несущих никаких сведений.