Введение: что такое монорепозиторий и зачем он нужен PHP-разработчику?
Разработка крупных PHP-проектов часто сталкивается с проблемой организации кода. Классический подход с отдельными репозиториями для каждого компонента (библиотеки, микросервисы, фронтенд) приводит к фрагментации, дублированию зависимостей и сложностям при рефакторинге. Альтернативой является монорепозиторий — единый репозиторий, содержащий все связанные проекты и пакеты.
В этой статье мы на практике разберем, как организовать монорепозиторий для PHP-проекта. Вы узнаете, как настроить Composer, структурировать папки, управлять зависимостями и организовать CI/CD. Статья ориентирована на PHP-разработчиков среднего уровня, знакомых с основами Git и Composer.
Основные преимущества монорепозитория:
- Единая история изменений и атомарные коммиты
- Простота рефакторинга общих зависимостей
- Унифицированные инструменты и конфигурации
- Упрощение CI/CD через единый пайплайн
Структура монорепозитория: выбираем правильную архитектуру
Ключевой элемент успешного монорепозитория — продуманная структура папок. Для PHP-проектов мы рекомендуем следующий шаблон, основанный на разделении на пакеты и приложения:
monorepo/
├── apps/ # Готовые приложения (веб-сайты, API, консольные скрипты)
│ ├── api/ # REST API на Slim или Laravel
│ │ ├── public/
│ │ ├── src/
│ │ └── composer.json
│ └── admin/ # Панель администратора
│ ├── public/
│ ├── src/
│ └── composer.json
├── packages/ # Многоразовые PHP-пакеты (библиотеки)
│ ├── core/ # Ядро системы: базовые классы, исключения
│ │ ├── src/
│ │ └── composer.json
│ ├── users/ # Пакет для управления пользователями
│ │ ├── src/
│ │ └── composer.json
│ └── payments/ # Платежный пакет
│ ├── src/
│ └── composer.json
├── tools/ # Сборочные и вспомогательные скрипты
├── tests/ # Интеграционные и E2E-тесты для всего проекта
├── composer.json # Корневой манифест (обычно "type": "project")
├── composer.lock
├── phpstan.neon
├── phpunit.xml.dist
└── .gitignore
Каждый пакет в packages/ — это самостоятельная Composer-библиотека со своим composer.json. Приложения в apps/ подключают эти пакеты как локальные зависимости. Такая структура позволяет:
- Изолировать логику и тестировать пакеты независимо
- Использовать строгую типизацию и автозагрузку PSR-4
- Переиспользовать код между разными приложениями без копирования
Настройка Composer для работы с монорепозиторием
Composer — основной инструмент управления зависимостями в PHP. Для работы с монорепозиторием мы используем два ключевых механизма: локальные пути (path) и корневой манифест.
Шаг 1: Корневой composer.json
В корне проекта создаем минимальный манифест, который определяет, что это монорепозиторий:
{
"name": "mycompany/monorepo",
"type": "project",
"require": {
"php": "^8.1"
},
"autoload": {
"psr-4": {
"MyCompany\\": "packages/"
}
},
"scripts": {
"test": "phpunit",
"phpstan": "phpstan analyse"
}
}
Шаг 2: Локальные зависимости в пакетах
Каждый пакет в packages/users/ должен иметь свой composer.json. Например:
{
"name": "mycompany/users",
"type": "library",
"require": {
"php": "^8.1",
"mycompany/core": "*"
},
"autoload": {
"psr-4": {
"MyCompany\\Users\\": "src/"
}
}
}
Обратите внимание: пакет mycompany/core указан как зависимость. Чтобы Composer понимал, что это локальный пакет, мы добавляем в корневой composer.json секцию repositories:
{
"repositories": [
{
"type": "path",
"url": "packages/*"
}
]
}
После этого выполняем composer update — Composer создаст символические ссылки на локальные пакеты. Это значит, что изменения в packages/core/src/ сразу отразятся во всех приложениях.
Шаг 3: Подключение пакетов в приложениях
Теперь в приложении apps/api/composer.json мы можем подключать локальные пакеты как обычные зависимости:
{
"name": "mycompany/api",
"require": {
"mycompany/users": "*",
"mycompany/payments": "*"
}
}
При запуске composer install в корне проекта все зависимости будут разрешены через локальные пути.
Работа с Git и CI/CD в монорепозитории
Монорепозиторий требует особого подхода к управлению версиями и автоматизации. Рассмотрим практические рекомендации.
Стратегия веток и коммитов
Используйте Trunk-based development или Git Flow с префиксами для указания области изменений:
feat/core-add-validator— новая функциональность в пакете corefix/api-login-error— исправление ошибки в приложении apirefactor/payments-structure— рефакторинг пакета payments
Атомарные коммиты должны затрагивать только один пакет или приложение. Это упрощает код-ревью и откат изменений.