Монорепозиторий с PHP: организация кода на практике

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: зачем монорепозиторий в PHP?

Разработка сложных PHP-приложений (CRM, SaaS, фреймворки) часто сталкивается с дилеммой: хранить весь код в одном репозитории (монорепозиторий) или разбить на множество микросервисов и пакетов. Монорепозиторий (monorepo) с PHP — это стратегия, при которой несколько связанных проектов (библиотек, модулей, приложений) находятся в едином Git-репозитории.

На практике это даёт:

  • Единую историю изменений — легче отследить, как изменение в одном пакете повлияло на другой.
  • Упрощённую настройку CI/CD — один конвейер для сборки и тестирования всех компонентов.
  • Снижение дублирования — общие конфиги, скрипты и зависимости.
  • Быструю итерацию — не нужно публиковать пакеты в Packagist для локального тестирования.

Однако монорепозиторий требует дисциплины. Без правильной организации кода он превращается в «спагетти-монолит». В этой статье мы разберём практические шаги по организации PHP-проекта в монорепозитории.

1. Структура каталогов монорепозитория

Ключевой принцип — чёткое разделение на пакеты и приложения. Рассмотрим на примере типовой архитектуры:

project-root/
├── apps/
│   ├── web/                  # Веб-приложение (Symfony/Laravel)
│   │   ├── public/
│   │   ├── src/
│   │   └── composer.json
│   └── api/                  # API-приложение (Lumen/Slim)
│       ├── public/
│       ├── src/
│       └── composer.json
├── packages/
│   ├── core/                 # Ядро (общие интерфейсы, сущности)
│   │   ├── src/
│   │   └── composer.json
│   ├── billing/              # Платёжный модуль
│   │   ├── src/
│   │   └── composer.json
│   └── notifications/        # Модуль уведомлений
│       ├── src/
│       └── composer.json
├── tools/                    # Скрипты разработки (PHP-CS-Fixer, PHPStan)
├── composer.json             # Корневой манифест
└── phpstan.neon              # Общие настройки анализа

Обратите внимание: каждый пакет в packages/ — это полноценная Composer-библиотека со своим composer.json. Это позволяет изолировать зависимости и тестировать их отдельно.

Пример composer.json для пакета core

{
    "name": "myproject/core",
    "type": "library",
    "autoload": {
        "psr-4": {
            "MyProject\\Core\\": "src/"
        }
    },
    "require": {
        "php": ">=8.1"
    },
    "extra": {
        "branch-alias": {
            "dev-main": "1.x-dev"
        }
    }
}

2. Управление зависимостями через Composer

Корневой composer.json — сердце монорепозитория. Он содержит:

  • Список всех пакетов, подключённых локально (через path репозиторий).
  • Dev-зависимости для всего проекта (PHPUnit, PHPStan, GrumPHP).
  • Скрипты для автоматизации (статический анализ, тесты).

Пример корневого composer.json

{
    "name": "myproject/monorepo",
    "type": "project",
    "repositories": [
        {
            "type": "path",
            "url": "packages/*",
            "options": {
                "symlink": true
            }
        }
    ],
    "require": {
        "myproject/core": "@dev",
        "myproject/billing": "@dev",
        "myproject/notifications": "@dev"
    },
    "require-dev": {
        "phpunit/phpunit": "^10.0",
        "phpstan/phpstan": "^1.10",
        "friendsofphp/php-cs-fixer": "^3.0"
    },
    "autoload": {
        "psr-4": {
            "MyProject\\": "packages/*/src/"
        }
    },
    "scripts": {
        "test": "phpunit",
        "analyse": "phpstan analyse",
        "cs-fix": "php-cs-fixer fix"
    }
}

Ключевые моменты:

  • symlink: true — изменения в пакетах сразу видны в корневом проекте (не нужно выполнять composer update).
  • @dev — позволяет подключать нестабильные версии пакетов (для локальной разработки).
  • Скрипты — запускаются из корня и применяются ко всем пакетам.

3. Настройка автозагрузки и тестирования

Чтобы PHPUnit и статический анализатор работали со всеми пакетами одновременно, нужно настроить конфигурацию на уровне монорепозитория.

phpunit.xml.dist (корневой)

<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php">
    <testsuites>
        <testsuite name="all">
            <directory>packages/*/tests</directory>
        </testsuite>
    </testsuites>
    <coverage>
        <include>
            <directory>packages/*/src</directory>
        </include>
    </coverage>
</phpunit>

phpstan.neon (корневой)

parameters:
    level: 8
    paths:
        - packages/*/src
        - apps/*/src
    excludePaths:
        - vendor
        - */tests

Теперь для запуска всех тестов достаточно выполнить в корне:

composer test

А для статического анализа:

composer analyse

4. CI/CD и автоматизация релизов

Монорепозиторий упрощает настройку CI. Вот пример пайплайна для GitHub Actions:

name: Monorepo CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions                

Блоги

Рекомендаций по книгам