Стандарты написания кода

Дата обновления перевода 2023-01-19

Стандарты написания кода

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

Эти стандарты кода Symfony основаны на стандартах PSR-1, PSR-2,`PSR-4`_ и PSR-12, так что вы уже можете знать большинство из них.

Как заставить ваш код следовать стандартам написания

Вместо того, чтобы вручную проверять ваш код, Symfony делает так, чтобы проверка соответствия отправленного вами когда ожидаемому синтаксису кода была максимально лёгкой. Для начала, установите инструмент PHP CS Fixer, а потом выполните эту команду, чтобы исправить любую проблему:

1
2
$ cd your-project/
$ php php-cs-fixer.phar fix -v

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

Стандарты написания кода Symfony в деталях

Если вы хотите узнать о стандартах написания кода Symfony в деталях, то вот краткий пример, содержащий большинство функций, описанных ниже:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/*
 * Этот файл является частью пакета Symfony.
 *
 * (c) Фабьен Потенсье <fabien@symfony.com>
 *
 * Чтобы получить полную информацию об авторском праве и лицензии, пожалуйста
 * просмотрите файл LICENSE, который поставляется с этим исходным кодом.
 */

namespace Acme;

use Other\Qux;

/**
 * Демонстрация стандартов написания кода.
 */
class FooBar
{
    public const SOME_CONST = 42;

    /**
     * @var string
     */
    private $fooBar;
    private $qux;

    /**
     * @param $dummy описание какого-то аргумента
     */
    public function __construct(string $dummy, Qux $qux)
    {
        $this->fooBar = $this->transformText($dummy);
        $this->qux = $qux;
    }

    /**
     * @deprecated
     */
    public function someDeprecatedMethod(): string
    {
        trigger_deprecation('symfony/package-name', '5.1', 'The %s() method is deprecated, use Acme\Baz::someMethod() instead.', __METHOD__);

        return Baz::someMethod();
    }

    /**
     * Преобразует ввод, заданный в качестве первого аргумента.
     *
     * @param $options коллекция опций для использования в рамках преобразования
     *
     * @throws \RuntimeException Когда предоставлена невалидная опция
     */
    private function transformText($dummy, array $options = [])
    {
        $defaultOptions = [
            'some_default' => 'values',
            'another_default' => 'more values',
        ];

        foreach ($options as $name => $value) {
            if (!array_key_exists($name, $defaultOptions)) {
                throw new \RuntimeException(sprintf('Unrecognized option "%s"', $name));
            }
        }

        $mergedOptions = array_merge($defaultOptions, $options);

        if (true === $dummy) {
            return 'something';
        }

        if (\is_string($dummy)) {
            if ('values' === $mergedOptions['some_default']) {
                return substr($dummy, 0, 5);
            }

            return ucwords($dummy);
        }

        return null;
    }

    /**
     * Выполняет некоторые базовые операции для заданного значения.
     */
    private function performOperations(mixed $value = null, bool $theSwitch = false)
    {
        if (!$theSwitch) {
            return;
        }

        $this->qux->doFoo($value);
        $this->qux->doBar($value);
    }
}

Структура

  • Добавляйте один пробел после каждой запятой-разграничителя;
  • Добавляйте один пробел вокруг бинарных операций(==, &&, ...), за исключением операции конкатенации (.);
  • Помещайте унарные операторы (!, --, ...) непосредственно с задействованной переменной;
  • Всегда используйте идентичное сравнение, кроме случаев, когда вам нужно жонглирование типами;
  • Используйте условия Йоды при сопоставлении переменной с выражением, чтобы избежать случайного назначения внутри выражения условия (это применимо к ==, !=, ===, и !==);
  • Добавляйте запятую после каждого объекта массива в многстрочном массиве, даже после последнего;
  • Добавляйте пустую строку перед утверждениями return, кроме случаев, когда возврат осуществляется внутри группы утвеждений (как утверждение if);
  • Используйте return null;, когда функция ясно возвращает значения null и используйте return;, когда функция возвращает значения void;
  • Не добавляйте возвратный тип void к методам в тестах;
  • Используйте скобки, чтобы обозначить тело структуры контроля независимо от количества содержащися в неё утверждений;
  • Определяйте один класс на файла - это не применимо к приватным классам помощников, которые не должны быть инстанциированы извне, и поэтому не рассматриваются автозагружаемыми стандартами PSR-0 and PSR-4;
  • Объявляйте наследуемость классов и все реализуемые интерфейсы в одной строке с именем класса;
  • Объявляйте свойства класса до методов;
  • Объявляйте сначала публичные методы, потом защищённые и потом - приватные. Исключением из этого правила являются конструктор класса и методы модульных PHP тестов setUp() и tearDown(), которые должны всегда быть первыми методами для большей удобочитаемости;
  • Объявляйте все аргументы в той же строке, что и имя метода или функции, независимо от того, сколько их. Единственным исключением являются методы конструктора, использующие продвижение свойства конструктора, где каждый параметр должен быть на новой строке с замыкающей запятой;
  • Используйте круглые скобки при инстанциировании классов, независимо от количества аргументов в конструкторе;
  • Строки исключений и сообщений ошибок должны быть конкатенированы используя sprintf;
  • Не используйте else, elseif, break после условий if и case, которые что-то вызывают или возвращают;
  • Не используйте пробелы вокруг относительного аксессора [ и перед относительным аксессором ].
  • Добавляйте утверждение use к каждому классу, который не является частью глобального пространства имен;
  • Когда PHPDoc теги вроде @param или @return включают в себя null и другие типы, всегда помещайте null в конце списка типов.

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

  • Используйте camelCase для переменных PHP, имен функций и методов, аргументов (например, $acceptableContentTypes, hasSession());
  • Используйте snake_case для параметров конфигурации и переменных шаблонов Twig (например, framework.csrf_protection, http_status_code);
  • Используйте SCREAMING_SNAKE_CASE для констант (например, InputArgument::IS_ARRAY);
  • Используйте UpperCamelCase для случаев исчисления (например, InputArgumentMode::IsArray);
  • Используйте пространства имён для всех PHP-классов и UpperCamelCase для их имен (например, ConsoleLogger);
  • Добавляйте ко всем абстрактным классам, кроме PHPUnit *TestCase, префикс Abstract. Пожалуйста отметьте, что некоторые ранние классы Symfony не следуют этому соглашению и не были переименованы по причинам обратной совместимости. Однако, все новые абстрактные классы должны следовать этому соглашению именования;
  • Добавляйте к интерфейсам суффикс Interface;
  • Добавляйте к чертам суффикс Trait;
  • Не используйте посвящённый суффикс для классов или исчислений (например, вроде Class или Enum), кроме случаев, описанных ниже.
  • Добавляйте к исключениям суффикс Exception;
  • Добавляйте к PHP-атрибутам префикс As, где это применимо (например, #[AsCommand] вместо #[Command], но #[When] остается как есть);
  • Используйте UpperCamelCase для именования PHP-файлов (например, EnvVarProcessor.php) и нижние подчеркивания для именования шаблонов Twig и веб-ресурсов (section_layout.html.twig, index.scss);
  • Для подсказок в PHPDocs и приведениях, используйте bool (вместо boolean или Boolean), int (вместо integer), float (вместо double или real);
  • Не забывайте смотреть в более подробный документ Соглашения для более субъективных правил именования.

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

  • Имя сервиса должно совпадать с полным именем класса (FQCN) его класса (например, App\EventSubscriber\UserSubscriber);
  • Если в одном классе существует несколько сервисов, используйте FQCN для главного сервиса, а для остальных используйте имена в нижнем регистре и с нижними подчёркиваниями. По желанию можете разделить их на группы, разделённые точками (например, something.service_name, fos_user.something.service_name);
  • Используйте буквы нижнего регистра для имён параметров (кроме случаев ссылания на переменные окружения с синтаксисом %env(VARIABLE_NAME)%);
  • Добавьте дополнитедьные имена для публичных сервисов (например, дополнительное имя

Symfony\Component\Something\ClassName к something.service_name).

Документация

  • Добавляйте блоки PHPDoc для всех классов, методов и функций только когда они добавляют релевантную информацию, которая не дублирует имя, заявление нативного типа или контекст (напимер, проверки instanceof);
  • Используйте только аннотации и типы, определённые в справочнике PHPDoc. Для того, чтобы улучшить типы для статичного анализа, следующие аннотации также разрешены:

  • Группируйте аннотации вместе, чтобы аннотации одного типа следовали сразу же друг за другом, а аннотации разных типов были разделены одной пустой строкой;
  • Опускайте тег @return, если метод ничего не возвращает;
  • Не используйте блоки PHPDoc одной строки в классах, методах и функциях, даже если они содержат только одну аннотацию (например, не размещайте /** {@inheritdoc} */ в одной строке);
  • При добавлении нового класса, или внесении существенных изменений в существующий класс, может быть добавлен или расширен тег @author с личными контактными данными. Пожалуйста, отметьте, что возможно обновлять или удалять личную информацию путем запроса к базовой команде.

Лицензия

  • Symfony выпускается под лицензией MIT, и блок лицензии должен присутствовать сверху каждого PHP-файла, перед пространством имён.