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

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

Код 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 в деталях, то вот краткий пример, содержащий большинство функций, описанных ниже:

/*
 * Этот файл является частью пакета Symfony.
 *
 * (c) Фабьен Потенсье <[email protected]>
 *
 * Чтобы получить полную информацию об авторском праве и лицензии, пожалуйста
 * просмотрите файл LICENSE, который поставляется с этим исходным кодом.
 */

namespace Acme;

use Other\Qux;

/**
 * Coding standards demonstration.
 */
class FooBar
{
    const SOME_CONST = 42;

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

    private $qux;

    /**
     * @param string $dummy Some argument description
     */
    public function __construct($dummy, Qux $qux)
    {
        $this->fooBar = $this->transformText($dummy);
        $this->qux = $qux;
    }

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

        return Baz::someMethod();
    }

    /**
     * Преобразует ввод, заданный в качестве первого аргумента.
     *
     * @param bool|string $dummy   Описание некоторого аргумента
     * @param array       $options Коллекция опций, которую нужно использовать при преобразовании
     *
     * @return string|null Трансформированный ввод
     *
     * @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;
    }

    /**
     * Выполняет некоторую базовую проверку заданного значения.
     *
     * @param mixed $value     Некоторое значение, которое нужно проверить
     * @param bool  $theSwitch Некоторый переключатель для контроля работы метода
     *
     * @return bool|void Резуультирующая проверка, если $theSwitch не false, иначе - void
     */
    private function performOperations($value = null, $theSwitch = false)
    {
        if (!$theSwitch) {
            return;
        }

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

Структура

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

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

  • Используйте camelCase для переменных PHP, имен функций и методов, аргументов (например, $acceptableContentTypes, hasSession());
  • Используйте snake_case для параметров конфигурации и переменных шаблонов Twig (например, framework.csrf_protection, http_status_code);
  • Используйте пространства имён для всех PHP-классов и UpperCamelCase для их имен (например, ConsoleLogger);
  • Добавляйте ко всем абстрактным классам, кроме PHPUnit *TestCase, префикс Abstract. Пожалуйста отметьте, что некоторые ранние классы Symfony не следуют этому соглашению и не были переименованы по причинам обратной совместимости. Однако, все новые абстрактные классы должны следовать этому соглашению именования;
  • Добавляйте к интерфейсам суффикс Interface;
  • Добавляйте к чертам суффикс Trait;
  • Добавляйте к исключениям суффикс 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);
  • Не забывайте смотреть в более подробный документ Conventions для более субъективных правил именования.

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

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

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

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

Лицензия

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

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.