Продолжаю рассказывать о своих проектах. Сегодня — Laramago, пакет для проверки Laravel-кода с помощью Mago. Уже вышла версия 0.1.5. Расскажу, откуда он появился, что умеет и почему для версии 1.0 мне нужны десять реальных проектов.

Зачем я его делаю
Хочется замечать ошибки ещё во время разработки. Mago умеет проверять PHP-код, находить проблемы с типами и форматировать файлы. Но у Laravel много своей магии: свойства моделей, связи, цепочки запросов, контейнер зависимостей. То, что привычно разработчику, анализатору нужно объяснить.
Для этого я и делаю Laramago. Хочу, чтобы проверки понимали устройство моих Laravel-проектов и помогали разбирать настоящие ошибки.
Как он создавался
Начал с Laravel-пресета и подключения через Composer. В первом релизе 0.0.1 уже были настройки линтера, форматирования и начальная поддержка вызовов Eloquent.
Постепенно добавлял сведения о свойствах моделей, связях, scopes, построителях запросов, коллекциях и конфигурации. Сценарии проверяю через сам Mago; поведение также сравниваю с Larastan. Если особенности приложения определить не удалось, важно сохранить диагностику, а не объявить код правильным.
Что есть сейчас
Пакет уже доступен на Packagist и используется в одном реальном проекте. Основной анализ читает исходники без запуска Laravel и подключения к базе. Это помогает работать со свойствами и связями моделей, уточнять типы результатов запросов и проверять поддерживаемые конструкции фреймворка.
В 0.1.5 добавил необязательный сборщик сведений о схеме базы для выбранных моделей. Пока он работает только с SQLite в файле и включается отдельно, с выполнением кода приложения. Одновременно улучшил проверку актуальности метаданных и исправил предупреждения в коде пакета.
Это рабочий предрелиз: возможностей уже немало, но опыт на разных приложениях ещё предстоит набрать.
Обновление от 16 октября: первые замеры
Проверил связку Mago и Laramago на одном реальном Laravel-приложении: 531 PHP-файл, около 102 тысяч строк. Название и код приложения оставляю за кадром. Сравнил её с PHPStan и Larastan, а также с Mago без расширений.
Для каждого варианта сделал прогрев и три измеряемых полных запуска в Linux с двумя CPU и лимитом памяти контейнера 6 ГиБ. Порядок инструментов менял между раундами. vendor был доступен только для чтения. PHPStan работал на уровне 10 с очищенным списком исключений конфигурации; аннотации в исходниках и остальные настройки проекта сохранялись. Кеш результатов PHPStan перед каждым запуском был пустым, дисковый кеш системы не очищал.
| Вариант | Медиана | Диапазон трёх запусков |
|---|---|---|
| Mago + Laramago 0.1.5 | 415,83 с | 405,72–524,25 с |
| PHPStan + Larastan, уровень 10 | 69,37 с | 54,99–73,67 с |
| Mago без расширений | 7,77 с | 7,60–7,78 с |
В этой серии Laramago заметно медленнее PHPStan с Larastan. Это результат на одном приложении и одной машине, с разными наборами проверок. Количество сообщений тоже нельзя превращать в счёт найденных ошибок: у инструментов различаются правила и уровни важности. По трём запускам универсальный рейтинг скорости не построить.
Как это соотносится с уровнями PHPStan
Глубину проверял отдельно от времени — на открытом наборе из 33 пар «ошибка и исправленный вариант», прогнав уровни PHPStan от 0 до 10 и Mago с расширением и без него. Поэтому назвать Laramago аналогом одного конкретного уровня PHPStan не могу.
Связка Mago и Laramago обнаруживает выбранные ошибки с mixed, которые в этом наборе появляются у PHPStan на уровнях 9 и 10. Но в проверенном режиме analyze пропускает три примера с отсутствующими аннотациями типов, которые PHPStan отмечает с уровня 6. Недостижимый код Mago в выбранном примере относит к подсказкам, а PHPStan — к ошибкам. Совпадение на отдельных примерах ещё не означает одинакового покрытия всего приложения.
Что буду ускорять
В отдельном диагностическом запуске увидел частые вытеснения деревьев разбора из кеша. У одного из двух обработчиков суммарный объём уникальных сериализованных деревьев составил около 132 МиБ при лимите кеша 64 МиБ; примерно 93,5% обращений завершились промахом. Эти данные относятся только к одному обработчику и пока не показывают, какую долю общего времени можно сэкономить.
Дальше хочу проверить ёмкость кеша и порядок обработки файлов, уменьшить повторный разбор исходников. Ускорение буду оценивать на полных запусках вместе с памятью и сохранением диагностики. Успешного ускорения всего анализа пока не заявляю.
Методика, полная матрица проверок и результаты замеров доступны в репозитории Laramago. Там же есть открытые примеры и скрипты для повторения проверок.
Почему до версии 1.0 ещё девять проектов
У меня простая схема версий. В 0.1.5 первая цифра 0 означает предрелиз, вторая 1 — число реальных проектов, где Laramago запущен, а третья 5 — патч-версию.
Когда Laramago заработает на десяти реальных проектах, выпущу 1.0. Для меня это будет основанием сказать: пакет проверен в работе на разных приложениях. Пока продолжаю подключать его к проектам, находить ограничения и исправлять их.
Описание и ссылки собрал на странице Laramago. Исходники — на GitHub, пакет — на Packagist. О следующих шагах буду писать под меткой Laramago.