Sie kennen die Situation: Ein PHP-Projekt läuft seit acht, zehn, vielleicht zwölf Jahren stabil im Produktivbetrieb. Es verdient Geld. Es tut, was es soll. Aber die Bibliotheken liegen als heruntergeladene ZIPs im Ordner lib/, PHPMailer wurde 2015 händisch reingekopiert, und niemand weiß mehr, welche Version des PDF-Generators eigentlich verwendet wird. Ein require_once jagt das nächste. Genau hier setzt die Frage an, wie Sie Composer in ein solches System einführen, ohne die funktionierende Fachlogik anzufassen.
Wichtig vorweg: Dass dieses System läuft, ist kein Zufall und kein Grund zur Häme. Es ist der Beweis, dass die Geschäftslogik trägt. Das Problem ist fast nie die Logik selbst, sondern der Code drumherum, der Ihnen die Wartung schwer macht. Composer ist eines der wirkungsvollsten Werkzeuge, um diesen Rahmen aufzuräumen, und Sie können es einführen, ohne eine einzige Zeile Fachlogik neu zu schreiben.
Warum sich das Composer einführen bei Legacy-Code lohnt
Ohne Dependency Management haben Sie drei chronische Probleme. Erstens: Sie wissen nicht sicher, welche Versionen Ihrer Bibliotheken laufen, und können Sicherheitslücken nicht systematisch schließen. Wenn eine CVE in einer alten PHPMailer-Version bekannt wird, müssen Sie manuell suchen, ob und wo sie betroffen sind. Zweitens: Updates sind reine Handarbeit und damit gefährlich. Drittens: Jeder neue Entwickler braucht Tage, um zu verstehen, welche externen Abhängigkeiten das Projekt eigentlich hat.
Composer löst das, indem es Abhängigkeiten deklarativ in einer composer.json festhält, exakte Versionen in der composer.lock einfriert und mit composer audit bekannte Schwachstellen meldet. Das ist kein kosmetisches Upgrade, sondern die Grundlage für alles Weitere: Autoloading, Testing, später vielleicht ein Framework. Und es ist der klassische Fall, in dem eine schrittweise Modernisierung um ein Vielfaches günstiger und risikoärmer ist als eine Neuentwicklung.
Der erste Schritt: composer.json anlegen, ohne etwas zu brechen
Sie beginnen im Projektwurzelverzeichnis mit composer init. Der interaktive Assistent fragt nach Name, Beschreibung und PHP-Version. Entscheidend: Fügen Sie in diesem Schritt noch keine Abhängigkeiten hinzu. Sie erzeugen zunächst nur eine leere, gültige composer.json. Führen Sie danach composer install aus. Es passiert scheinbar nichts Spektakuläres, aber Sie haben jetzt ein vendor/-Verzeichnis und einen zentralen Autoloader.
Ein häufiger, unnötiger Fehler an dieser Stelle: Menschen versuchen sofort, alles auf einmal umzustellen. Tun Sie das nicht. Committen Sie diese leere composer.json, deployen Sie sie, prüfen Sie, dass die Anwendung unverändert läuft. Ein kleiner, verifizierbarer Schritt ist bei Legacy-Systemen immer besser als ein großer Sprung.
Bestehende Bibliotheken durch Composer-Pakete ersetzen
Jetzt gehen Sie Ihre manuell eingebundenen Bibliotheken eine nach der anderen durch. Nehmen wir PHPMailer als typisches Beispiel. Im Projekt liegt es unter lib/phpmailer/ und wird per require eingebunden. Sie ermitteln zunächst die verwendete Version (oft steht sie in einer VERSION-Datei oder im Klassen-Header) und installieren dann bewusst genau diese oder eine kompatible:
composer require phpmailer/phpmailer:^6.0
Danach entfernen Sie die alten require-Statements für PHPMailer und ersetzen sie durch den Composer-Autoloader. Wenn der alte Code noch mit vollqualifizierten Klassennamen ohne Namespace arbeitet, müssen Sie eventuell die Aufrufe von new PHPMailer() auf new PHPMailer\PHPMailer\PHPMailer() anpassen. Das ist überschaubar und lässt sich per Suchen-und-Ersetzen erledigen. Wichtig ist die Reihenfolge: eine Bibliothek umstellen, testen, committen. Dann die nächste. Niemals fünf gleichzeitig.
Für Bibliotheken, die es nicht auf Packagist gibt, haben Sie zwei Optionen: ein privates Repository via repositories in der composer.json, oder Sie belassen sie vorerst im Projekt und binden sie über den Classmap-Autoloader ein. Nicht jede Abhängigkeit muss im ersten Durchlauf perfekt sein.
Das eigene Projekt an den Autoloader anbinden
Der eigentliche Gewinn kommt, wenn Sie Ihren eigenen Code über Composer laden lassen. Bei Legacy-Projekten ohne Namespaces ist der Classmap-Autoloader der pragmatische Einstieg. Sie tragen in der composer.json ein:
"autoload": { "classmap": ["src/", "includes/"] }
Nach composer dump-autoload scannt Composer diese Verzeichnisse und findet Ihre Klassen anhand der Dateinamen, auch ohne PSR-4-Struktur. Damit können Sie nach und nach die verstreuten require_once-Aufrufe für eigene Klassen entfernen. Jedes gelöschte require_once ist eine potenzielle Fehlerquelle weniger.
Erst wenn das läuft, denken Sie über eine schrittweise Migration einzelner Bereiche auf PSR-4-Namespaces nach. Das ist kein Muss für den Start und sollte Sie nicht davon abhalten, den ersten Nutzen zu heben. Sie können Classmap und PSR-4 problemlos parallel betreiben.
Sicherheit und Wartbarkeit als sofortiger Nutzen
Sobald Ihre Abhängigkeiten in der composer.json stehen, führen Sie composer audit aus. Sie sehen jetzt zum ersten Mal schwarz auf weiß, welche Ihrer Bibliotheken bekannte Sicherheitslücken haben. Bei einem Projekt, das jahrelang mit eingefrorenen ZIPs lief, ist dieses erste Audit oft ein Augenöffner, im positiven Sinne, denn nun können Sie gezielt handeln statt zu raten.
Nehmen Sie die composer.lock ernst und committen Sie sie immer mit. Sie garantiert, dass auf allen Systemen exakt dieselben Versionen installiert werden. In der Produktion deployen Sie dann mit composer install --no-dev --optimize-autoloader, was den Autoloader für den Produktivbetrieb optimiert und Entwicklungswerkzeuge außen vor lässt.
Ein ehrlicher Praxis-Tipp zum Schluss
Die größte Gefahr bei dieser Migration ist nicht technischer Natur, sondern die Versuchung, zu viel auf einmal zu wollen. Widerstehen Sie ihr. Führen Sie Composer ein, stellen Sie eine einzige Bibliothek um, deployen Sie, atmen Sie durch. Erst dann die nächste. Ein System, das seit Jahren läuft, verdient diesen Respekt, und Ihr Betrieb dankt es Ihnen mit stabilen Deployments. Wenn Sie an einem verwinkelten Legacy-System festhängen oder eine unabhängige Einschätzung brauchen, ob ein bestimmter Schritt sicher ist, begleitet LegacyWerk genau solche Modernisierungen ohne Big-Bang-Risiko.