Monorepository mit PHP: Code-Organisation und Best Practices
In der modernen PHP-Entwicklung stellt sich zunehmend die Frage nach einer effizienten Code-Organisation. Der traditionelle Ansatz mit vielen separaten Repositories (Multi-Repository) hat seine Nachteile: Komplexität bei der Versionssynchronisation, doppelte Konfigurationen und Probleme beim Refactoring. Eine Alternative ist das Monorepository (Monorepo) – eine Strategie, bei der alle zusammenhängenden Projekte, Pakete und Bibliotheken in einem einzigen Repository gespeichert werden. In diesem Artikel werden wir uns ansehen, wie man ein Monorepository mit PHP organisiert, welche Tools man verwendet und welche Fallstricke zu beachten sind.
Was ist ein Monorepository und warum wird es für PHP-Projekte benötigt?
Ein Monorepository ist ein einheitlicher Code-Speicher, der mehrere Projekte oder Pakete enthält. In der PHP-Welt ist Laravel ein klassisches Beispiel, das das Framework, Pakete für Authentifizierung, Warteschlangen, E-Mail und andere Komponenten in einem Repository umfasst.
Die wichtigsten Vorteile für PHP-Projekte:
- Vereinfachtes Refactoring – Änderungen in einem Paket sind sofort für alle abhängigen Komponenten sichtbar, es ist nicht nötig, Versionen jedes Pakets separat zu veröffentlichen und zu aktualisieren.
- Versionsintegrität – alle Pakete verwenden dieselbe Version von Abhängigkeiten, was Typkonflikte ausschließt.
- Einheitliche CI/CD – eine einzige Build-Pipeline für alle Komponenten, vereinfachtes Testen von paketübergreifenden Änderungen.
- Verbesserte Zusammenarbeit – Entwickler sehen den gesamten Code des Projekts, Code-Reviews sind einfacher und einheitliche Codierungsstandards werden leichter eingehalten.
Allerdings ist ein Monorepository nicht für jeden geeignet. Wenn Ihre Projekte lose gekoppelt sind oder unterschiedliche Release-Zyklen haben, kann ein Multi-Repository bequemer sein. Für mittlere und große PHP-Projekte mit enger Integration der Komponenten ist das Monorepository oft die optimale Wahl.
Struktur eines Monorepositorys in PHP
Die richtige Struktur ist die Grundlage eines erfolgreichen Monorepositorys. Betrachten wir eine typische Organisation am Beispiel eines Projekts mit einem Kern (core), mehreren Modulen und Tests.
my-php-monorepo/├── packages/│ ├── core/│ │ ├── src/│ │ │ └── CoreService.php│ │ ├── tests/│ │ └── composer.json│ ├── module-auth/│ │ ├── src/│ │ ├── tests/│ │ └── composer.json│ └── module-payment/│ ├── src/│ ├── tests/│ └── composer.json├── apps/│ ├── api/│ │ ├── public/│ │ ├── src/│ │ └── composer.json│ └── console/│ ├── src/│ └── composer.json├── tests/│ └── IntegrationTest.php├── composer.json (root)├── phpunit.xml.dist├── .gitignore└── README.mdWichtige Organisationsprinzipien:
- Aufteilung in Pakete (packages) – jedes Paket hat seine eigene
composer.jsonmit Namen, Autoloading und Abhängigkeiten. - Anwendungen (apps) – Einstiegspunkte (API, Konsolenbefehle), die die Pakete zusammenführen.
- Root composer.json – enthält die Meta-Konfiguration für die Arbeit mit dem Monorepository.
Einrichtung der Root composer.json
Für die Arbeit mit dem Monorepository muss die root composer.json so konfiguriert werden, dass die Pakete lokal verfügbar sind, ohne Veröffentlichung auf Packagist.
{ "name": "my-company/my-monorepo", "type": "project", "require": { "php": "^8.1", "my-company/core": "*", "my-company/module-auth": "*", "my-company/module-payment": "*" }, "autoload": { "psr-4": { "MyCompany\\\\": "packages/" } }, "repositories": [ { "type": "path", "url": "packages/*", "options": { "symlink": true } } ], "scripts": { "test": "phpunit", "cs-fix": "php-cs-fixer fix" }}```