Введение
Разработка на PHP часто начинается с одного файла index.php, но по мере роста проекта возникает необходимость структурировать код. Многие разработчики сталкиваются с дилеммой: хранить всё в одном репозитории (монорепозиторий) или разбить на множество маленьких репозиториев (мультирепозиторий). В этой статье мы разберём концепцию монорепозитория для PHP-проектов, покажем, как организовать код для начинающих, и приведём практические примеры.
Монорепозиторий (monorepo) — это подход, при котором код нескольких проектов, библиотек или компонентов хранится в одном репозитории системы контроля версий (Git). В контексте PHP это означает, что ваш основной сайт, API, пакеты и утилиты находятся в одной папке. Это упрощает управление зависимостями, рефакторинг и развёртывание.
В этой статье вы узнаете:
- Что такое монорепозиторий и зачем он нужен
- Как организовать структуру папок для PHP
- Как настроить Composer для работы с монорепозиторием
- Примеры реальной организации кода
Преимущества монорепозитория для PHP
Многие начинающие PHP-разработчики считают, что монорепозиторий — это "свалка кода". На самом деле, при правильной организации это мощный инструмент. Вот основные плюсы:
- Простота навигации: Все компоненты проекта находятся в одном месте. Не нужно переключаться между репозиториями.
- Единая версия зависимостей: Вы используете один файл
composer.jsonдля управления пакетами, что исключает конфликты версий. - Атомарные коммиты: Изменения в API, фронтенде и библиотеках можно делать в одном коммите, что упрощает откат.
- Упрощённое тестирование: Интеграционные тесты проходят быстрее, так как все компоненты доступны локально.
- Единый CI/CD: Один конвейер сборки для всего проекта.
Однако монорепозиторий подходит не всем. Если ваша команда большая (более 20 человек), или проекты сильно различаются по технологиям, лучше рассмотреть мультирепозиторий. Для начинающих и средних проектов — это идеальный выбор.
Структура монорепозитория: базовая схема
Давайте создадим типовую структуру PHP-монорепозитория. Предположим, у нас есть веб-приложение с API и несколькими библиотеками. Вот рекомендуемая иерархия папок:
my-php-monorepo/
├── apps/
│ ├── web/ # Основной сайт (Laravel, Symfony или чистый PHP)
│ │ ├── public/
│ │ ├── src/
│ │ └── config/
│ └── api/ # API-сервер
│ ├── public/
│ ├── src/
│ └── routes/
├── packages/ # Внутренние библиотеки и пакеты
│ ├── core/ # Ядро системы (базовые классы)
│ │ ├── src/
│ │ └── composer.json
│ ├── database/ # Работа с БД (миграции, модели)
│ │ ├── src/
│ │ └── composer.json
│ └── utils/ # Утилиты (валидация, логирование)
│ ├── src/
│ └── composer.json
├── tests/ # Глобальные тесты
├── docker/ # Docker-конфиги
├── composer.json # Корневой Composer
├── composer.lock
├── .gitignore
└── README.md
Пояснение:
apps/— содержит исполняемые приложения (сайты, API, консольные скрипты). Каждое приложение имеет свою точку входа (public/index.php).packages/— внутренние пакеты, которые вы разрабатываете. Они подключаются черезcomposer.jsonс использованиемpath-репозиториев.tests/— корневые тесты (например, интеграционные тесты, которые проверяют взаимодействие между пакетами).docker/— файлы для Docker (Dockerfile, docker-compose.yml).
Настройка Composer для монорепозитория
Ключевой момент — правильно настроить composer.json в корне проекта. Composer должен знать о ваших внутренних пакетах. Используем репозиторий типа path.
Пример корневого composer.json:
{
"name": "my-php-monorepo/root",
"require": {
"php": "^8.1",
"monolog/monolog": "^3.0",
"my-php-monorepo/core": "*",
"my-php-monorepo/database": "*",
"my-php-monorepo/utils": "*"
},
"repositories": [
{
"type": "path",
"url": "packages/*",
"options": {
"symlink": true
}
}
],
"autoload": {
"psr-4": {
"App\\Web\\": "apps/web/src/",
"App\\Api\\": "apps/api/src/"
}
},
"scripts": {
"test": "phpunit",
"cs-fix": "php-cs-fixer fix"
}
}
Теперь создадим пакет packages/core/composer.json:
{
"name": "my-php-monorepo/core",
"description": "Core library for my PHP monorepo",
"type": "library",
"autoload": {
"psr-4": {
"MyMonorepo\\Core\\": "src/"
}
},
"require": {
"php": "^8.1"
}
}
После этого выполните composer update в корне проекта. Composer создаст символическую ссылку на ваш пакет, и вы сможете разрабатывать его локально, изменения будут сразу видны в приложениях.
Пример использования внутреннего пакета
Создадим класс в packages/core/src/Logger.php:
<?php
namespace MyMonorepo\Core;
class Logger
{
public function log(string $message): void
{
echo "[" . date('Y-m-d H:i:s') . "] " . $message . PHP_EOL;
}
}
Теперь в приложении