Патчинг PHP-пакетов, установленных через Composer

Быстрые ссылки
Когда стоит патчить пакет
Создание патча для Composer
Создание файла патча
Автоматическое применение патчей
Удаление патчей
Когда стоит патчить пакет
Перед тем как патчить зависимость внутри проекта, оцените альтернативы. Патч внутри проекта должен быть небольшим, целевым и временным. Патчи уместны, если они:
- Исправляют критическую ошибку, блокирующую релиз или работу приложения.
- Влияют на несколько строк кода и не вносят архитектурных изменений.
- Не предназначены для постоянного расширения функциональности библиотеки.
Когда патч не подходит:
- Нужно добавить крупную функциональность — лучше форкнуть пакет или предложить PR в upstream.
- Требуется изменить публичный API библиотеки — тогда лучше создать обёртку (adapter/wrapper) в своём коде.
- Патч предполагает внесение изменений, затрагивающих множество файлов — это повышает риск конфликтов при обновлениях.
Короткая формула принятия решения: если исправление срочное и локальное — патч уместен; если это долгосрочное изменение дизайна — выбирайте PR/форк/обёртку.
Создание патча для Composer
Composer не поддерживает патчи «из коробки», поэтому рекомендуется использовать пакет-обёртку, который упрощает рабочий процесс. Популярный выбор — symplify/vendor-patches, который предоставляет удобные команды поверх cweagans/composer-patches.
Установите пакет разработки:
composer require --dev symplify/vendor-patchesУбедитесь, что нужный пакет уже установлен в проекте:
composer require example/broken-packageОткройте файл, который нужно исправить, в каталоге vendor. В примере мы редактируем:
vendor/example/broken-package/src/Broken.phpИсходный (проблемный) файл в примере выглядит так:
Здесь автор намеревался принимать и строки, и числа (union-тип string|int в PHP 8), но реализация фактически обрабатывает только строки. Допустим, автор уже в курсе проблемы, но новый релиз ещё не выпущен — можно временно патчить.
Процесс безопасного создания патча:
- Скопируйте оригинал в файл с суффиксом .old (без изменений) — он будет использоваться для расчёта diff:
cp vendor/example/broken-project/src/Broken.php vendor/example/broken-project/src/Broken.php.old- Не редактируйте файл .old.
- Отредактируйте оригинальный файл vendor/example/broken-project/src/Broken.php так, чтобы он корректно работал в вашем коде. Патчи применяются в момент установки зависимостей, поэтому изменения сразу влияют на выполнение вашего приложения.
Исправленный пример:
Проверьте поведение вашего приложения локально перед генерацией патча.
Создание файла патча
После того как вы внесли изменения, используйте vendor-patches для генерации файла патча. Утилита сканирует каталог vendor и сравнивает текущие файлы с их .old-версиями.
Запустите генерацию:
vendor/bin/vendor-patches generateКоманда создаст diff и сохранит его в каталоге patches в корне проекта. Каждый изменённый файл даёт отдельный .patch.
Советы по патчу:
- Держите патч минимальным: только те изменения, которые необходимы для исправления.
- Добавляйте заголовок и описание в тело .patch, чтобы коллеги понимали, зачем он нужен.
- Версионируйте патчи в системе контроля версий вместе с коммитом, который изменил файл .old и сгенерировал патч.
Автоматическое применение патчей
После генерации патчей ваш composer.json должен содержать секцию extra.patches. Пример структуры в composer.json:
{
"extra": {
"patches": {
"example/broken-package": [
"patches/example-broken-package-src-broken-php.patch"
]
}
}
}Обёртка регистрирует установочный скрипт, который при установке или обновлении зависимостей проверяет наличие патчей и пытается их применить. При выполнении composer install вы увидите строки в выводе, подтверждающие применение патча.
Если патч пропускается, запустите с подробным выводом для диагностики:
composer install --verboseЧастые причины пропуска патчей:
- upstream уже исправил проблему в новой версии пакета — патч становится неактуальным.
- Структура файлов изменилась, и патч не может быть применён чисто.
- Патч конфликтует с другим патчем или локальными изменениями.
Удаление патчей
Чтобы временно отключить патч — удалите соответствующую строку в composer.json. Чтобы полностью удалить патч из проекта:
- Удалите запись в composer.json в секции extra.patches.
- Удалите .patch-файл из каталога patches.
- При необходимости удалите пакет из vendor и выполните composer install для восстановления чистого состояния.
Если вы хотите откатить локально применённый патч, проще всего удалить или отключить запись и переустановить зависимости.
Когда патч не подойдёт (примеры и контрпримеры)
Подходит:
- Небольшая правка байткода или логики, мешающая запуску приложения.
- Исправление уязвимости безопасности до выхода исправления в upstream.
Не подходит:
- Требуется добавить новую подсистему или изменить публичный API — тогда лучше форк или PR.
- Патч перекрывает тесты пакета и требует изменений множества модулей — высок риск регрессий.
Важно: храните в патче ссылку на issue/PR в upstream, чтобы позже проверить, можно ли удалить патч.
Альтернативные подходы
- Создать PR (pull request) в репозитории пакета — лучший вариант для долгосрочного решения.
- Форкнуть пакет и использовать собственную версию через репозиторий или VCS-ссылку в composer.json.
- Обёртка (adapter/wrapper): написать свой класс, который инкапсулирует вызовы проблемного API и предоставляет нужный интерфейс.
- Временно заменить пакет другим, если это приемлемо по объёму работ.
Каждый подход имеет свои плюсы и минусы по затратам на поддержку, совместимости и скорости внедрения.
Мини-методика: как безопасно применять патч в команде
- Оцените изменение и подтвердите, что оно минимально и безопасно.
- Создайте .old-файлы и сгенерируйте патч локально.
- Добавьте патч в каталог patches и зафиксируйте в VCS с подробным сообщением и ссылкой на issue.
- Откройте MR/PR в вашем репозитории, чтобы коллеги могли проверить патч.
- После проверки и слияния документируйте патч и назначьте владельца для мониторинга upstream.
- Как только upstream решит проблему — удалите патч.
Чек-лист по ролям
Разработчик:
- Подготовил .old и сгенерировал патч.
- Написал краткое описание в патче и ссылку на issue.
- Проверил, что тесты проходят с патчем.
Ревьюер/ведущий команды:
- Оценил риск изменения и согласовал временность решения.
- Проверил отсутствие побочных эффектов в смежных областях.
Релиз-инженер / DevOps:
- Убедился, что CI применяет патчи и артефакты собираются.
- Контролирует вывод composer install и логи применения патчей.
Модель принятия решения — блок-схема
flowchart TD
A[Возникла ошибка в зависимости] --> B{Можно ли обойти проблему без изменений в пакете?}
B -- Да --> C[Применить обход 'конфигурация/обёртка']
B -- Нет --> D{Изменение минимально и временно?}
D -- Да --> E[Сделать патч в проекте]
D -- Нет --> F{Возможен PR или форк?}
F -- PR --> G[Открыть PR в upstream и ждать релиз]
F -- Форк --> H[Форкнуть пакет и использовать свой VCS-репозиторий]
E --> I[Сгенерировать .patch и добавить в composer.json]
I --> J[Контролировать и удалять после релиза]Критерии приёмки
- Патч минимален и документирован.
- Тесты на критические сценарии проходят с патчем.
- В PR указана ссылка на issue в upstream и план удаления патча после релиза.
- Есть ответственный за мониторинг состояния upstream.
Глоссарий (одной строкой)
- Патч — diff-файл, который изменяет файлы пакета при установке.
- upstream — исходный репозиторий пакета, где поддерживается проект.
- .old-файл — копия оригинала, используемая для генерации diff.
Примечания и рекомендации
- Храните патчи в VCS и давайте им понятные имена, отражающие пакет и файл.
- Регулярно проверяйте upstream на исправления, чтобы вовремя удалить патчи.
- По возможности создавайте PR в upstream: это снижает технический долг и нагрузку на вашу команду.
Важное: патчи — мощный инструмент экстренной починки, но они несут долгосрочные издержки. Используйте их осознанно и документируйте каждое изменение.
Итог
Патчинг пакетов Composer — рабочая стратегия для быстрого исправления проблем, когда upstream ещё не выпустил релиз. Использование symplify/vendor-patches упрощает генерацию и автоматическое применение патчей. Всегда документируйте патчи, поддерживайте их в VCS и планируйте удаление, как только upstream решит проблему.
Похожие материалы
Как научиться программировать бесплатно
Как редактировать скриншоты на Android
Перенос Microsoft Authenticator на новый телефон
Список рассылки в Outlook 2013/2016
Исправление входа в GDM на Fedora 22