Laravel: Используем PHP Codesniffer

Источник: «Using PHP Codesniffer With Laravel»
Давайте рассмотрим как установить и настроить PHP Codesniffer с новым Laravel проектом.

Начиная с Laravel 9 в пакет поставки входит Laravel Pint. Я обожаю Pint и для большинства людей достаточно его использования для форматирования стиля кода. До Laravel Pint я предпочитал комбинацию PHP CS Fixer и PHP Codesniffer — оба превосходны в тандеме и предлагают уникальные правила для соблюдения стиля кода.

Стиль длинны строки кода один из примеров того, как PHP Codesniffer может дополнять такие инструменты, как PHP CS Fixer, и мы можем использовать оба, чтобы придерживаться согласованного стиля кода. Если вы используете PSR-12, секция Lines содержит следующую информацию о длине строк:

НЕ ДОЛЖНО быть жёстких ограничений на длину строки.

Мягкое ограничение длинны строки ДОЛЖНО составлять 120 символов.

Строки НЕ ДОЛЖНЫ быть длиннее 80 символов; строки длиннее этого СЛЕДУЕТ разбивать на несколько последовательных строк не более 80 символов каждая.

Наши инструменты CI могут применять как мягкие, так и жёсткие ограничения длинны строки, но я интерпретирую PSR-12 так, что PHP Codesniffer должен предупреждать нас и не возвращать никаких ошибок для строк длинной > 80. Мы расскажем об этом далее в статье.

Давайте разберёмся с настройкой PHP Codesniffer для нового Laravel проекта, а затем в последующих руководствах узнаем как создать собственный стандарт PHP Codesniffer, который можно использовать во всех наших проектах.

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

Установка

Первое, что мы сделаем, создадим пример проекта, чтобы вы могли увидеть, как интегрировать PHP Codesniffer с Laravel с нуля:

laravel new phpcs-part-1 --git
cd phpcs-part-1

Флаг --git установит новое приложение Laravel, инициализирует git и передаст всё в систему управления версиями. Это оставляет нам чистое состояние, чтобы увидеть какие изменения мы вносим в этом руководстве.

Далее установим PHP Codesniffer в качестве зависимости для разработки:

composer require --dev squizlabs/php_codesniffer

Примечание. На момент написания статьи устанавливается версия ^3.7, но ваша версия может немного отличаться, что не имеет значения.

Если вы запустите команду phpcs из командной строки, то увидите, что она хочет, чтобы вы указали путь:

$ vendor/bin/phpcs
ERROR: You must supply at least one file or directory to process.

Run "phpcs --help" for usage information

Не волнуйтесь, мы добавим файл конфигурации с указанием какие пути PHPCS должен включать (а какие исключать). Если вы его запустите с набором правил по умолчанию (Pear), то получите кучу ошибок для Laravel установленного по умолчанию:

$ vendor/bin/phpcs -v app
Registering sniffs in the PEAR standard... DONE (28 sniffs registered)
....

FILE: /Users/paul/code/sandbox/phpcs-part-1/app/Providers/AppServiceProvider.php
--------------------------------------------------------------------------------
FOUND 2 ERRORS AFFECTING 2 LINES
--------------------------------------------------------------------------------
2 | ERROR | Missing file doc comment
7 | ERROR | Missing doc comment for class AppServiceProvider
--------------------------------------------------------------------------------

Если вы проверите код выхода, то увидите, что PHPCS выдаёт ошибки для выхода с ненулевым кодом:

$ echo $?
2

Хочу внести ясность: эти ошибки возникают не потому, что ваш код плохо отформатирован (как раз наоборот), а потому, что мы используем стандарт PEAR по умолчанию, которому Laravel не следует по умолчанию.

Давайте рассмотрим использование другого стандарта и создание файла конфигурации.

Изучение инструментов командной строки

Прежде чем добавлять файл конфигурации phpcs в наш проект, давайте посмотрим как этаже конфигурация будет выглядеть с использованием командной строки. Мы знаем, что не хотим использовать PEAR, поэтому давайте сначала запустим команду PHPCS со встроенным стандартом PSR-12.

vendor/bin/phpcs --standard=PSR12 app

Если внимательно посмотреть на вывод, то можно заметить, что стандарт PSR-12 для PHP Codesniffer хочет исправить некоторые предупреждения вокруг конкатенации строк:

FILE: /Users/paul/code/sandbox/phpcs-part-1/app/Console/Kernel.php
----------------------------------------------------------------------
FOUND 2 ERRORS AFFECTING 1 LINE
----------------------------------------------------------------------
28 | ERROR | [x] Expected at least 1 space before "."; 0 found
28 | ERROR | [x] Expected at least 1 space after "."; 0 found
----------------------------------------------------------------------
PHPCBF CAN FIX THE 2 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------

[x] означает что мы можем исправить эти предупреждения автоматически (не все предупреждения можно исправить автоматически) с помощью phpcbf поставляемого с Codesniffer. Мы доберёмся до него через секунду.

Во-первых, давайте посмотрим на несколько других флагов, которые я предпочитаю использовать. Как только начинаете использовать PHP Codesniffer в разработке и CI, я замечаю, что полное имя предупреждения не видно. Возможно вы захотите настроить это предупреждение, игнорировать его в определённой строке и т.д.

Что бы видеть полный анализ в командной строке вы можете использовать флаг -s:

vendor/bin/phpcs -s --standard=PSR12 app

Вот пример, как выглядит вывод со всеми предупреждениями:

FILE: /Users/paul/code/sandbox/phpcs-part-1/app/Console/Kernel.php
----------------------------------------------------------------------
FOUND 2 ERRORS AFFECTING 1 LINE
----------------------------------------------------------------------
28 | ERROR | [x] Expected at least 1 space before "."; 0 found
| | (PSR12.Operators.OperatorSpacing.NoSpaceBefore)
28 | ERROR | [x] Expected at least 1 space after "."; 0 found
| | (PSR12.Operators.OperatorSpacing.NoSpaceAfter)
----------------------------------------------------------------------
PHPCBF CAN FIX THE 2 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------

Вы можете видеть найденное предупреждение PSR12.Operators.OperatorSpacing.NoSpaceBefore в приведённом выше пример. Если мы хотим его игнорировать в файле Kernel.php, мы можем отключить проверку в файл app/Console/Kernel.php где-то в 28 строке:

// phpcs:disable PSR12.Operators.OperatorSpacing.NoSpaceAfter
$this->load(__DIR__.'/Commands');
// phpcs:enable

Если повторно запустим команду — на этот раз мы увидим, что правило NoSpaceAfter отключено для этой строки, но всё равно получим ошибку NoSpaceBefore:

vendor/bin/phpcs -s --standard=PSR12 app/Console/Kernel.php

FILE: /Users/paul/code/sandbox/phpcs-part-1/app/Console/Kernel.php
----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
----------------------------------------------------------------------
29 | ERROR | [x] Expected at least 1 space before "."; 0 found
| | (PSR12.Operators.OperatorSpacing.NoSpaceBefore)
----------------------------------------------------------------------
PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------

Можно отключить несколько правил для заданного набора строк, разделив их запятыми следующим образом:

// phpcs:disable PSR12.Operators.OperatorSpacing.NoSpaceAfter, PSR12.Operators.OperatorSpacing.NoSpaceBefore
$this->load(__DIR__.'/Commands');
// phpcs:enable

Наконец, давайте отменим все изменения, внесённые в файл app/Console/Kernel.php. Вы обнаружите, что эти два правила использованные в качестве примера, напрямую конфликтуют с Laravel Pint, который ожидает пробелы до и после.

Во-первых, давайте автоматически исправим приведённые выше предупреждения с помощью phpcbf:

vendor/bin/phpcbf --standard=PSR12 app

PHPCBF RESULT SUMMARY
----------------------------------------------------------------------------------------------
FILE FIXED REMAINING
----------------------------------------------------------------------------------------------
/Users/paul/code/sandbox/phpcs-part-1/app/Models/User.php 1 0
/Users/paul/code/sandbox/phpcs-part-1/app/Http/Controllers/Controller.php 1 0
/Users/paul/code/sandbox/phpcs-part-1/app/Console/Kernel.php 2 0
----------------------------------------------------------------------------------------------
A TOTAL OF 4 ERRORS WERE FIXED IN 3 FILES
----------------------------------------------------------------------------------------------

После этого давайте запустим Laravel Pint, посмотреть что он делает обратное тому, что PHP Codesniffer исправил автоматически:

$ vendor/bin/pint
FIXED 54 files, 1 style issue fixed
✓ app/Console/Kernel.php concat_space

Чтобы мы могли использовать оба инструмента во время разработки и в средах CS, нужно выбрать стиль и применить его с помощью одного инструмента и отключить с помощью другого. Я предпочитаю автоматические исправления от Pint, поэтому отключаю конкурирующие предупреждение в PHP Codesniffer.

Файл конфигурации

Давайте разрешим конфликт между Pint и Codesniffer, создав файл конфигурации. В приложении я обычно использую phpcs.xml, но если планируете позволить другим использовать приложение в качестве отправной точки, можно рассмотреть возможность использования phpcs.xml.dist. Давайте создадим его как phpcs.xml:

<?xml version="1.0"?>
<!-- @see https://pear.php.net/manual/en/package.php.php-codesniffer.annotated-ruleset.php -->
<ruleset name= "Laravel PHPCS Rules">

<description>PHPCS ruleset for Example app.</description>

<file>tests</file>
<file>app</file>

<!-- Show progress of the run -->
<arg value= "p"/>

<!-- Show sniff codes in all reports -->
<arg value= "s"/>

<!-- Our base rule: set to PSR12 -->
<rule ref="PSR12">
<exclude name="PSR12.Operators.OperatorSpacing.NoSpaceBefore"/>
<exclude name="PSR12.Operators.OperatorSpacing.NoSpaceAfter"/>
</rule>

<rule ref= "Generic.Files.LineLength">
<properties>
<property name="lineLimit" value="80"/>
<property name="absoluteLineLimit" value="120"/>
</properties>
</rule>
<rule ref="PSR1.Methods.CamelCapsMethodName.NotCamelCaps">
<exclude-pattern>tests/</exclude-pattern>
</rule>

</ruleset>

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

Мы отключили проверку пробелов между операторами, так что Pint должен быть доволен, а PHP Codesniffer будет игнорировать эти правила.

Мы также настроили правило длинны строк, используя PSR-12 в качестве ориентира для ограничений строк и максимального значения. Эти предупреждения отображаются, поэтому когда вы запускаете этот инструмент в CI, вы должны убедиться, либо предупреждения подавляются, либо CI их игнорирует. Предупреждения предназначены для разработчика, помочь исправить длину строк в процессе разработки.

Наконец предупреждение NotCamelCaps исключено для директории test, потому что мне нравиться писать PHPUnit со змеиным регистром:

/* @test */
public function it_does_something_awesome()

Теперь мы можем запустить phpcs без каких-либо аргументов, и он подхватит наш файл конфигурации. Вы должны видеть только предупреждения о длине строки множественном импорте.

vendor/bin/phpcs

Ещё одно нарушение которое вы заметите — это анализ MultipleImport, связанный, например, с этой строкой:

class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
// ...
}

Не стесняйтесь отключать этот анализ, если хотите, или можете исправлять его автоматически (используя файл конфигурации) с помощью команды phpcbf:

vendor/bin/phpcbf
.........F..........F.. 23 / 23 (100%)

PHPCBF RESULT SUMMARY
----------------------------------------------------------------------------------------------
FILE FIXED REMAINING
----------------------------------------------------------------------------------------------
/Users/paul/code/sandbox/phpcs-part-1/app/Models/User.php 1 0
/Users/paul/code/sandbox/phpcs-part-1/app/Http/Controllers/Controller.php 1 0
----------------------------------------------------------------------------------------------
A TOTAL OF 2 ERRORS WERE FIXED IN 2 FILES
----------------------------------------------------------------------------------------------

Заключение

Мы рассмотрели довольно мало вопросов, но вы сможете начать использовать PHP Codesniffer с нуля с Laravel. Это может быть отличным дополнением, если вы хотите настроить таргетинг на конкретные правила, которые PHP CS Fixer не выполняет. Я рассказал, как отключить конфликтующие правила или правила, которые вы просто хотите отключить.

Похожие статьи

Дополнительные материалы

Предыдущая Статья

Laravel API: Переопределе­ние Сообщения об Ошибке 404

Следующая Статья

Laravel: Как обрабатывать длительные задания