Pull to refresh

Автоматизированная проверка PHP кода при комитах

Reading time 6 min
Views 33K
В свое время работая в узком кругу программистов, отдельными задачами и даже проектам, мы не задумывались о проблемах связанными с текучкой кадров. Точнее думать — думали, но ни каких мер не применяли, да и в целом коллектив был сплоченный никто не уходил и никого «не уходили». С ростом внутренних проектов и корпоративных клиентов, штат начал разрастаться и казалось, что все отлично — нас больше, значит будем больше успевать и делать, но не тут то было. Мы начали тратить кучу времени на “бесполезные” обсуждения, проверки, излишние проектирование и т.д, больше всего раздражает — это проверка кода. И тут я начал думать, что “мудрые и древние” наверняка решали эти проблемы с сотнями, тысячами программистов, неужели мы не справимся? Я решил провести эксперимент, под названием “автоматизированная проверка стиля кода при комитах”. Для большинства из Вас это не новость и наверняка вы этим пользуетесь, но поделиться опытом внедрения думаю, не будет лишним.

Воскресения, 3:40

В это ранние время, сидя за работой и сделав перерыв на чай, я задумался, завтра нужно ехать в офис и снова утром тратить 2 — 3 часа на проверку кода, потом еще 2 часа на постановку задач, итого 5 часов, потом может быть поработать 2 часа и ехать домой. И понятное дело, что задачи которые поставили, я не могу решить за оставшиеся 2 — 3 часа, а решая эти проблемы в неурочное время могу разрушить свою семью и т.д. Так дальше не может продолжаться. В первую очередь я программер, а не «цербер» и нужно автоматизировать процесс проверки, это если не снимет все время проверки, то хотя бы сократит.
Не люблю изобретать колесо, потому сразу обратился к поисковику и задал запрос: «checking coding standards PHP», просматривая первый десяток результатов обратил внимание на часто встречающийся название "PHP_Codesniffer" и задав одноименный запрос — увидел, что это PEAR библиотека для автоматизированной проверки стиля кода, как говориться -«то что, доктор прописал!» и надежности разработчиков сомневаться не приходиться, что благотворно повлияет при возможном глобальном внедрении. Установив на сервер библиотеку:

pear install PHP_CodeSniffer-1.3.0RC1

Предполагаться, что у вас установлен дистрибутив PEAR на сервере. После установки станет доступна новая служба phpcs:

phpcs --standard=Zend your.php

Не много поигравшись, меня порадовало, что уже данное решение поддерживает многие стандарты: Squiz, MySource, PHPCS, Zend, PEAR. Меня это устраивало, так как мы утвердили в свое время, что будем кодить согласно стандарту Zend.
Про затачивания это библиотеки можно почитать в официально документации

Воскресение, 4:00

Окрыленный своей находкой и быстрым ее “поднятием”, сон отступил. Первая задача была решена, теперь осталось подключить это решения к контролю версий при комите. В документации к PHP_CodeSniffer есть раздел посвященный описанию интеграции с SVN — это было хорошо, так как у нас SVN любят использовать, но я использую GIT и решил писать свой хук для git и тут думаю: “не верю, что на PEARовское решения нет описания интеграции c GIT”. И снова обратившись к поисковику нашел готовое решение phpcs-pre-commit:

git clone https://github.com/s0enke/git-hooks.git

Для интеграции этого хука нужно положить файлик pre-commit в папку hooks вашего git репозитория (.git/hooks). Кто интересовался git хуками — тот в теме.
И последние проверка коммита мне вывелась таблица с описание ошибок не соблюдения стиля. Не буду приводить пример того, как отображает таблицу ошибок phpcs, да и зачем. В .git/hooks/pre-commit нужно указать какой стиль вы хотите использовать:

PHPCS_CODING_STANDARD=Zend

Также укажите расширения файлов которые необходимо проверять:

PHPCS_FILE_PATTERN="\.(php|phtml)$"

Если при комите вам выдает ошибку:
error: cannot run .git/hooks/pre-commit: No such file or directory
Это значит, что указан не правильный путь к bash, измените его в .git/hooks/pre-commit

Задача в целом решена, плюс CodeSniffer в том, что с ним обязанность проверять “юношеские” ошибки, которые свойственны всем — отпадает. И главный плюс, что заставит “молодых” просматривать код как минимум при поиски ошибки стиля и возможно проведения минимального рефакторинга.
Теперь можно в понедельник ехать на работу и рассказать об нововведениях. Если это поможет нам, то можно будет идти лоббировать интеграцию данного решения для всех.

Понедельник, 17:00

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

PEAR_PATH/PHP/CodeSniffer/Standards/

PEAR_PATH — это путь к папке с PEAR библиотеками у нас на сервере они располагаются в /usr/local/share/pear/.

Для создания своего стиля создайте папку YOUR_STYLE в PEAR_PATH/PHP/CodeSniffer/Standards/.

В паке вашего стиля нужно создать ruleset.xml. Про формат этого файла можно почитать тут, опишу только-то, что пригодилось мне.
Связи с тем, что требования кодированию максимально приближены к Zend стилю, просто скопировал содержание с PEAR_PATH/PHP/CodeSniffer/Standards/Zend/ruleset.xml:
<?xml version="1.0"?>
<ruleset name="Zend">
<description>A coding standard based on an early Zend Framework coding standard. Note that this standard is out of date.</description>

<!-- Include some sniffs from all around the place -->
<rule ref="Generic.Functions.FunctionCallArgumentSpacing"/>
<rule ref="Generic.Functions.OpeningFunctionBraceBsdAllman"/>
<rule ref="Generic.PHP.DisallowShortOpenTag"/>
<rule ref="Generic.WhiteSpace.DisallowTabIndent"/>
<rule ref="PEAR.Classes.ClassDeclaration"/>
<rule ref="PEAR.ControlStructures.ControlSignature"/>
<rule ref="PEAR.Functions.FunctionCallSignature"/>
<rule ref="PEAR.Functions.ValidDefaultValue"/>
<rule ref="PEAR.WhiteSpace.ScopeClosingBrace"/>
<rule ref="Squiz.Functions.GlobalFunction"/>

<!-- Lines can be 80 chars long, show errors at 120 chars -->
<rule ref="Generic.Files.LineLength">
<properties>
 <property name="lineLimit" value="120"/>
 <property name="absoluteLineLimit" value="140"/>
</properties>
</rule>

<!-- Use Unix newlines -->
<rule ref="Generic.Files.LineEndings">
<properties>
 <property name="eolChar" value="\n"/>
</properties>
</rule>
</ruleset>


В теге ruleset замените имя на свое имя YOUR_STYLE и добавляю одно правило с Zend:

<rule ref="Zend.Debug.CodeAnalyzer"/>

Для отключения верблюжьего стиля копирую:
PEAR_PATH/PHP/CodeSniffer/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php в PEAR_PATH/PHP/CodeSniffer/Standards/YOUR_STYLE/Sniffs/NamingConventions/ValidVariableNameSniff.php. Переименовав класс с Zend_Sniffs_NamingConventions_ValidVariableNameSniff на YOUR_STYLE_Sniffs_NamingConventions_ValidVariableNameSniff, добавил:

public $isCheckCamelCaps;

И добавил везде проверку на этот “флажок”. Теперь если нужно будет его переопределить — это можно будет сделать из ruleset.xml:
<rule ref="YOUR_STYLE.NamingConventions.ValidVariableName">
<properties>
 <property name="isCheckCamelCaps" value="1"/>
</properties>
</rule>


Вторник, 19:00

Повсплывало много моментов на которые свое время закрывались глаза, но пришло время их приводить в порядок! Самой полезной проверкой стиля кода оказалась проверка на длину строки кода, и благодаря ее было зарефакторено много нечитабельных мест.
Правда столкнулись с проблемой с русскими комментариями, код весь хранится в UTF-8, а CodeSniffer длину строки проверяет стандартным strlen и логично что строки увеличивались в два раза. Не стал я заморачиваться на переопределения класса, что было бы правильнее, а просто в PEAR_PATH/PHP/CodeSniffer/Standards/Generic/Sniffs/Files/LineLengthSniff.php добавил:

public $charset = 'UTF-8';

и заменил strlen, на:

mb_strlen($lineContent, $this->charset)

Суббота

Прошла нелегкая неделя с CodeSniffer, и вот какие плюсы:
  • Снимается время и нервы на проверку стиля кода;
  • при исправление ошибок длины строк, пересматриваешь логику кода, что благотворно влияет на читабельность кода и проведения рефакторинга мутной логики. Также снимается надобность объяснять когда одно-строчные if хорошо, а когда плохо;
  • снимается обязанность следить за документацией стиля кодирования;
  • поддерживает проверку всех популярных стандартов кодинга.

Минусы:
  • Неудобно внедрять в “исторические” проекты или чужие, можно потратить несколько дней, а то и недель на наведения икебаны;
  • не удобно внедрять с контроль версиями, так как без напильника не подымешь, что для GIT, что для SVN. Особенно когда проектов несколько десятков и не для всех одинаковый стиль кодинга.
Tags:
Hubs:
+64
Comments 48
Comments Comments 48

Articles