Монорепозиторий с PHP: организация кода для масштабируемых проектов
В современной PHP-разработке управление кодом становится критически важным по мере роста проекта. Традиционный подход с множеством отдельных репозиториев (полирепозиторий) часто приводит к проблемам синхронизации, дублированию зависимостей и сложностям при рефакторинге. Альтернатива — монорепозиторий (Monorepo), когда весь код, включая библиотеки, утилиты и приложения, хранится в одном Git-репозитории. В этой статье мы разберем, как организовать монорепозиторий на PHP, используя Composer, Git и современные инструменты.
Что такое монорепозиторий и зачем он нужен в PHP?
Монорепозиторий — это единый репозиторий, содержащий несколько проектов, пакетов или модулей, которые могут быть логически связаны. Для PHP-разработчика это означает, что ядро фреймворка, API-сервис, административная панель и общие библиотеки находятся в одной папке.
Преимущества монорепозитория:
- Единая версионность: Все изменения коммитятся атомарно — исправление в библиотеке сразу сопровождается обновлением кода, который её использует.
- Упрощение рефакторинга: Вы можете изменить интерфейс пакета и сразу обновить все зависимости в рамках одного pull request.
- Стандартизация инструментов: Один файл
composer.jsonдля корня, единые правила линтинга и тестирования. - Снижение дублирования: Общий код (например, DTO, хелперы) не нужно публиковать в Packagist — он доступен напрямую.
Однако монорепозиторий требует дисциплины: без чёткой структуры он превращается в «свалку». Ключ к успеху — правильная организация с помощью Composer autoload и Git-сабмодулей или специализированных инструментов вроде monorepo-builder.
Структура монорепозитория на PHP
Рассмотрим типовую структуру для PHP-проекта, где есть несколько библиотек и одно приложение. Корневой каталог выглядит так:
my-monorepo/
├── packages/
│ ├── core/ # Базовая библиотека (ядро)
│ │ ├── src/
│ │ │ └── CoreClass.php
│ │ └── composer.json
│ ├── logger/ # Логирование
│ │ ├── src/
│ │ └── composer.json
│ └── api/ # API-пакет (может быть отдельным приложением)
│ ├── src/
│ │ └── Controllers/
│ └── composer.json
├── apps/
│ └── web/ # Веб-приложение (Laravel/Symfony)
│ ├── public/
│ ├── src/
│ └── composer.json
├── composer.json # Корневой composer.json (мета-пакет)
├── phpunit.xml.dist
└── .gitignore
Принципы организации:
- Все пакеты находятся в
packages/. Каждый пакет имеет собственныйcomposer.jsonс уникальным именем (например,mycompany/core). - Приложения (фронт, админка, API) лежат в
apps/. Они могут использовать пакеты изpackages/как локальные зависимости. - Корневой
composer.jsonслужит для глобальной конфигурации (autoload, скрипты).
Настройка Composer для работы с монорепозиторием
Чтобы PHP-автозагрузка работала без публикации пакетов на Packagist, используем path-репозитории. Добавьте в корневой composer.json следующий блок:
{
"name": "mycompany/monorepo",
"require": {
"mycompany/core": "*",
"mycompany/logger": "*"
},
"repositories": [
{
"type": "path",
"url": "packages/*"
}
],
"autoload": {
"psr-4": {
"MyCompany\\": "packages/"
}
},
"scripts": {
"test": "phpunit"
}
}
Теперь при выполнении composer install Composer создаст симлинки на локальные пакеты. Это значит, что изменения в packages/core/src/CoreClass.php сразу отразятся в приложении без переустановки зависимостей.
Пример пакета packages/core/composer.json:
{
"name": "mycompany/core",
"type": "library",
"autoload": {
"psr-4": {
"MyCompany\\Core\\": "src/"
}
},
"require": {
"php": ">=8.1"
}
}
Обратите внимание: неймспейсы должны быть уникальными. Для пакета core используем MyCompany\Core, для logger — MyCompany\Logger.
Git-стратегии для монорепозитория
Работа с Git в монорепозитории требует особого подхода, чтобы не «засорять» историю коммитами из разных несвязанных пакетов. Рекомендуемые практики:
- Feature branches: Создавайте ветки для каждой фичи, даже если она затрагивает несколько пакетов. Коммитьте атомарно: один коммит — одно логическое изменение.
- Commit messages с префиксами: Используйте соглашение
[core],[api]или[web]в начале сообщения, чтобы было понятно, какой пакет изменён. Пример:[logger] Добавлен метод logError(). - Избегайте сабмодулей: В классическом монорепозитории Git-сабмодули не нужны — все файлы находятся в одном репозитории. Если требуется изолировать историю пакетов, рассмотрите
git subtreeили инструментmonorepo-builder(symplify/monorepo-builder).
Пример использования monorepo-builder:
Установите пакет:
composer require --dev symplify/monorepo-builder
Создайте
Блоги
Рекомендаций по книгам
Читайте также