Deprecated Code erkennen und migrieren, bevor er hart entfernt wird
Deprecation Handling ist kein Punkt auf der Upgrade-Checkliste, sondern ein laufender Prozess: PHPStan-Regeln, Composer-Audits und CI-Gates decken deprecated Code auf, lange bevor Magento ihn in einer künftigen Major-Version entfernt und die Migration erzwingt.
Inhaltsverzeichnis
- 1. Warum Deprecation Handling ein kontinuierlicher Prozess ist
- 2. Wie Magento Code als deprecated markiert
- 3. Deprecated Code technisch erkennen: PHPStan
- 4. Deprecation auf Composer-Ebene
- 5. Automatisierte Erkennung in der CI-Pipeline
- 6. Migrationsstrategien: Rector und Plugin-Migration
- 7. Priorisierung: welche APIs zuerst?
- 8. Team-Prozess und Dokumentation
- 9. Praxisbeispiel: eine konkrete Migration
- 10. Zusammenfassung
- 11. FAQ
1. Warum Deprecation Handling ein kontinuierlicher Prozess ist, kein einmaliges Upgrade-Projekt
Deprecation Handling wird in vielen Teams mit dem letzten Schritt vor einem großen Versions-Upgrade verwechselt: kurz vor der Migration auf eine neue Magento-Version wird hektisch nach veraltetem Code gesucht, weil sonst nichts mehr funktioniert. Tatsächlich ist Deprecation Handling etwas anderes: ein kontinuierlicher Bestandteil des Entwicklungsalltags, der bei jedem Composer-Update, jedem Kern-Patch und jeder neuen Feature-Entwicklung greift. Magento markiert in praktisch jeder Minor-Version APIs, Klassen und Methoden als deprecated, lange bevor sie in einer künftigen Major-Version tatsächlich entfernt werden. Wer Deprecation Handling nur alle paar Jahre betreibt, sammelt in der Zwischenzeit unbemerkt technische Schulden an, die sich bei der nächsten großen Migration zu einem echten Blocker summieren.
Der Unterschied zwischen einer einmaligen Versions-Migration und laufendem Deprecation Handling liegt im Zeitpunkt der Kostenentstehung. Wird deprecated Code über Jahre ignoriert, entsteht am Ende ein Big-Bang-Refactoring mit hohem Risiko, engem Zeitfenster und wenig Testabdeckung für die betroffenen Stellen. Wird Deprecation Handling hingegen als Teil des normalen Entwicklungsflusses etabliert, verteilen sich dieselben Änderungen über viele kleine, gut testbare Commits. Jeder Pull Request, der neuen Code gegen eine bereits als deprecated markierte API schreibt, ist ein vermeidbarer Fehler, der sich mit den richtigen Werkzeugen schon vor dem Merge verhindern lässt.
Die Backward-Compatibility-Policy von Magento gibt Entwicklerteams zwar mehrere Jahre Vorlauf, bevor eine deprecated API tatsächlich verschwindet, doch dieser Vorlauf ist kein Grund zur Untätigkeit. Im Gegenteil: Er ist die Gelegenheit, Deprecation Handling in Sprint-Planung, Code-Reviews und CI-Pipeline zu verankern, statt ihn als Sonderprojekt zu behandeln. Die folgenden Abschnitte zeigen, wie sich deprecated Code technisch zuverlässig erkennen lässt und mit welchen Migrationsstrategien er sich systematisch abbauen lässt, bevor Magento ihn hart entfernt.
2. Wie Magento Code als deprecated markiert: @deprecated-Annotationen, @see-Verweise, Backward-Compatibility-Policy
Magento kennzeichnet veralteten Code über die PHPDoc-Annotation @deprecated, ergänzt um eine Versionsnummer, ab der die Markierung gilt, etwa @deprecated 101.0.0. Diese Versionsnummer bezieht sich nicht auf die Magento-Produktversion, sondern auf die interne Modulversion des jeweiligen Composer-Pakets, was bei der Interpretation häufig zu Verwirrung führt. Direkt unter der @deprecated-Zeile folgt meist ein @see-Verweis, der auf die empfohlene Ersatzklasse, -methode oder -schnittstelle zeigt. Ein sauber dokumentierter deprecated Code-Block liefert also nicht nur die Information "nicht mehr verwenden", sondern auch die konkrete Migrationsrichtung.
Die Backward-Compatibility-Policy von Magento unterscheidet zusätzlich zwischen Code, der mit @api als offizielle, stabile Schnittstelle markiert ist, und internem Code ohne diese Kennzeichnung. Für @api-Code gilt eine deutlich striktere Zusage: Er wird über mehrere Minor-Versionen hinweg nicht ohne vorherige Deprecation-Phase entfernt. Interner, nicht als @api markierter Code kann sich hingegen auch ohne formale Deprecation-Ankündigung zwischen Patch-Releases ändern. Wer Deprecation Handling ernst nimmt, unterscheidet deshalb zwischen offiziell deprecated API-Oberflächen und stillschweigend geänderten internen Implementierungsdetails, die PHPStan allein nicht immer vollständig erfasst.
Wichtig für die Praxis: Eine @deprecated-Annotation entfernt eine Methode nicht sofort, sie bleibt in der Regel voll funktionsfähig, oft über mehrere Jahre. Genau das verleitet Teams dazu, die Warnung zu ignorieren. Deprecation Handling bedeutet deshalb nicht Panik bei jedem einzelnen Fund, sondern ein systematisches Erfassen, Priorisieren und schrittweises Abarbeiten dieser Annotationen, bevor die Gnadenfrist der Backward-Compatibility-Policy abläuft.
3. Deprecated Code technisch erkennen: PHPStan mit phpstan/phpstan-deprecation-rules, bin/analyse
Manuelles Durchsuchen des Codes nach @deprecated-Kommentaren skaliert in einer gewachsenen Magento-Codebasis nicht. Der zuverlässige Weg für technisches Deprecation Handling ist statische Analyse mit PHPStan und der Erweiterung phpstan/phpstan-deprecation-rules. Diese Regel-Erweiterung analysiert nicht den Kommentartext, sondern den tatsächlichen Aufruf-Graphen: Sie erkennt jede Stelle im eigenen Code, an der eine als deprecated markierte Klasse instanziiert, eine deprecated Methode aufgerufen oder ein deprecated Interface implementiert wird, unabhängig davon, ob die Annotation im aufrufenden Code selbst sichtbar ist.
Im Mark-Shust-Docker-Setup wird PHPStan über den Wrapper bin/analyse ausgeführt, etwa mit bin/analyse app/code/Mironsoft --level=5. Damit dieser Aufruf auch Deprecation-Verstöße meldet, muss die Konfigurationsdatei phpstan.neon die Deprecation Rules explizit über includes einbinden. Ohne diesen Include analysiert PHPStan zwar Typen, Rückgabewerte und Nullability korrekt, deprecated Aufrufe fallen aber komplett durch das Raster, weil sie kein eigenständiges PHPStan-Level bilden, sondern eine separate Regel-Erweiterung sind.
# File: phpstan.neon
# Enables continuous Deprecation Handling as part of static analysis
includes:
- vendor/phpstan/phpstan-deprecation-rules/rules.neon
- phpstan-baseline.neon
parameters:
level: 5
paths:
- app/code/Mironsoft
- app/code/Abrams
excludePaths:
- */Test/*
- */vendor/*
reportUnmatchedIgnoredErrors: true
Die Datei phpstan-baseline.neon spielt dabei eine strategische Rolle: Sie friert den aktuellen Bestand an bekannten deprecated Aufrufen ein, sodass bin/analyse nicht sofort mit hunderten Fehlern gegen einen historisch gewachsenen Bestand fehlschlägt. Neue Nutzung deprecated Codes, die nicht Teil der Baseline ist, lässt PHPStan hingegen sofort auffliegen. Diese Kombination aus Baseline und Deprecation Rules ist der Kern eines funktionierenden, technisch erzwungenen Deprecation Handlings, weil sie bestehende Schulden sichtbar hält, ohne die tägliche Entwicklungsarbeit zu blockieren.
4. Deprecation auf Composer-Ebene: veraltete Abhängigkeiten, Marketplace-Modul-Hinweise, composer outdated
Deprecation Handling betrifft nicht nur eigenen Code, sondern auch Composer-Abhängigkeiten. Der Befehl bin/composer outdated --direct zeigt, welche direkten Abhängigkeiten neuere Versionen verfügbar haben, verrät aber nicht automatisch, ob ein Paket als abandoned markiert wurde. Genau dieses Flag ist für Deprecation Handling entscheidend: Composer kennzeichnet Pakete, deren Maintainer sie offiziell aufgegeben haben, oft mit einem Verweis auf einen empfohlenen Nachfolger. Der Befehl bin/composer show --all --direct kombiniert mit grep -i abandoned macht diese Hinweise im laufenden Betrieb sichtbar, ohne dass man jede composer.json einzeln durchsuchen muss.
Für Drittanbieter-Module aus dem Magento Marketplace gilt eine zusätzliche Ebene: Der Marketplace selbst weist im Modul-Changelog und in der Produktbeschreibung häufig auf deprecated Funktionen hin, etwa wenn ein Zahlungsanbieter eine alte API-Version einstellt oder ein Modul-Hersteller eine Klasse zugunsten einer neuen Schnittstelle als veraltet kennzeichnet. Diese Hinweise erscheinen nicht in PHPStan-Reports, weil sie oft nur in der Dokumentation stehen, nicht im Code selbst als @deprecated annotiert sind. Ein vollständiges Deprecation Handling muss deshalb auch Release-Notes und Marketplace-Ankündigungen von eingesetzten Drittmodulen regelmäßig sichten, nicht nur den eigenen Codebestand.
Praktisch bedeutet das: composer outdated als Routineaufgabe in jedem Sprint, kombiniert mit einer kurzen Prüfung, ob unter den veralteten Paketen abandoned Pakete oder Marketplace-Module mit angekündigten Breaking Changes sind. Wer diesen Composer-Check mit der PHPStan-Analyse aus Abschnitt 3 kombiniert, deckt sowohl selbst geschriebenen deprecated Code als auch veraltete Fremdabhängigkeiten ab, die beide Teil desselben Deprecation-Handling-Prozesses sind.
5. Automatisierte Erkennung in der CI-Pipeline: Build-Fail bei neuer Nutzung deprecated Codes
Manuelles Ausführen von bin/analyse auf dem Entwickler-Rechner ist ein guter Anfang, verhindert aber nicht zuverlässig, dass deprecated Code in den Hauptzweig gelangt, wenn ein Entwickler den Check vor dem Commit vergisst. Der entscheidende Schritt für nachhaltiges Deprecation Handling ist deshalb, dieselbe PHPStan-Konfiguration als verpflichtendes Gate in die CI-Pipeline zu integrieren. Jeder Merge Request durchläuft dann automatisch dieselbe Analyse, und ein Build schlägt fehl, sobald neuer Code eine deprecated API nutzt, die nicht bereits Teil der Baseline ist.
In einer GitLab-CI-Pipeline lässt sich dieses Gate als eigene Stage abbilden, die nach dem Composer-Install läuft und denselben bin/analyse-Aufruf verwendet wie lokal. Wichtig ist, den Job so zu konfigurieren, dass er bei jedem Merge Request läuft, nicht nur bei Releases, damit Deprecation Handling frühestmöglich im Entwicklungsprozess greift und nicht erst kurz vor einem Deployment auffällt.
stages:
- analyse
deprecation-check:
stage: analyse
image: mironsoft/php84-magento:latest
script:
- bin/composer install --no-interaction --prefer-dist
- bin/analyse app/code/Mironsoft --level=5 --no-progress
- bin/analyse app/code/Abrams --level=5 --no-progress
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
allow_failure: false
Der Parameter allow_failure: false ist hier bewusst gesetzt: Ein Deprecation-Fund soll den Merge blockieren, nicht nur als Warnung im Pipeline-Log verschwinden. Teams, die diesen harten Gate-Ansatz scheuen, weil die Baseline noch zu groß ist, können in einer Übergangsphase mit einem separaten, nicht blockierenden Job starten und erst nach Abbau der größten Altlasten auf allow_failure: false umstellen. Entscheidend ist, dass Deprecation Handling nicht dem guten Willen einzelner Entwickler überlassen bleibt, sondern strukturell in der Pipeline verankert ist.
6. Migrationsstrategien: Rector für automatisiertes Refactoring, Plugin- statt Preference-Migration
Nicht jede Migration von deprecated Code muss manuell erfolgen. Das Tool Rector automatisiert einen großen Teil des Deprecation Handlings, indem es abstrakte Syntaxbäume analysiert und definierte Umschreibungsregeln anwendet, etwa das Ersetzen einer deprecated Methode durch ihren dokumentierten Nachfolger oder das Entfernen toten Codes rund um eine veraltete Bedingung. Für Magento-spezifische Migrationen existieren zusätzlich Community-Regelsets, die typische Magento-Deprecation-Muster kennen, etwa veraltete Event-Namen oder deprecated Konstruktor-Signaturen.
Eine rector.php-Konfigurationsdatei definiert, welche Pfade analysiert werden und welche Regelsets angewendet werden sollen. Rector arbeitet dabei nie destruktiv im Blindflug: Der Standardmodus zeigt zunächst nur ein Diff der geplanten Änderungen an, erst mit dem Flag --dry-run deaktiviert oder dem expliziten Ausführen ohne dieses Flag werden Dateien tatsächlich geschrieben. Für ein Team, das Deprecation Handling in großem Maßstab betreibt, ist Rector damit kein Ersatz für Code-Review, sondern ein Werkzeug, das die immer gleichen, mechanischen Teile der Migration vorab erledigt.
Eine der häufigsten manuellen Migrationen betrifft den Wechsel von Preference-basiertem Überschreiben auf Plugins. Preferences in di.xml ersetzen eine komplette Klasse und brechen bei jedem Core-Update, sobald sich die überschriebene Klasse ändert, was viele Magento-Preferences faktisch zu latenten Deprecation-Kandidaten macht, auch ohne explizite @deprecated-Annotation. Plugins (Interceptors) hingegen greifen nur an definierten Methoden-Grenzen ein und sind deutlich robuster gegenüber Core-Änderungen. Die Migration von Preference zu Plugin ist deshalb häufig Teil desselben Deprecation-Handling-Backlogs wie die Migration explizit markierter deprecated APIs.
<?php
declare(strict_types=1);
use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\SetList;
return static function (RectorConfig $rectorConfig): void {
// Only touch Mironsoft's own module code, never vendor or core
$rectorConfig->paths([
__DIR__ . '/app/code/Mironsoft',
]);
$rectorConfig->sets([
SetList::DEAD_CODE,
SetList::CODE_QUALITY,
]);
$rectorConfig->skip([
__DIR__ . '/app/code/Mironsoft/*/Test',
__DIR__ . '/app/code/Mironsoft/*/etc',
]);
// Keep import statements tidy after automated rewrites
$rectorConfig->importNames();
$rectorConfig->parallel();
};
7. Priorisierung: welche deprecated APIs zuerst migrieren
Kein Team kann jeden Fund aus PHPStan, Composer-Audit und Marketplace-Hinweisen gleichzeitig abarbeiten. Deprecation Handling braucht deshalb eine Priorisierungslogik, die über reines "zuerst gefunden, zuerst behoben" hinausgeht. Bevor priorisiert werden kann, hilft ein Überblick, welche Erkennungsmethode welchen Erkennungsgrad, welchen Automatisierungsgrad und welchen Aufwand mitbringt.
| Methode | Erkennungsgrad | Automatisierbar | Aufwand |
|---|---|---|---|
| PHPStan Deprecation Rules | Sehr hoch, erfasst Aufruf-Graph | Ja, vollständig | Niedrig nach Ersteinrichtung |
| Manuelles Code-Review | Mittel, abhängig vom Reviewer | Nein | Hoch, pro Review |
| Composer-Audit | Hoch für Abhängigkeiten | Ja, per Skript | Niedrig |
| Magento-Marketplace-Hinweise | Niedrig, nur Dokumentation | Nein | Mittel, manuelle Sichtung |
| IDE-Inspektionen | Mittel, nur beim Bearbeiten sichtbar | Teilweise | Sehr niedrig |
Zwei Kriterien bestimmen die Priorisierung im Deprecation Handling in der Praxis: Nutzungshäufigkeit und Nähe zur tatsächlichen Entfernung. Eine deprecated Methode, die an zwanzig Stellen im Code aufgerufen wird, verursacht bei einer erzwungenen Migration deutlich mehr Schaden als eine, die nur an einer Stelle genutzt wird, selbst wenn beide dieselbe Versionsnummer in der @deprecated-Annotation tragen. Ebenso wichtig ist das Alter der Markierung: Eine API, die bereits seit @deprecated 100.0.2 markiert ist, ist der Entfernung strukturell näher als eine, die erst kürzlich in @deprecated 103.0.0 markiert wurde, weil Magento ältere Deprecations tendenziell zuerst in kommenden Major-Versionen entfernt. Ein einfaches Scoring, das beide Faktoren kombiniert, liefert eine belastbare Reihenfolge für den Migrations-Backlog.
8. Team-Prozess und Dokumentation: Deprecation-Register, Tech-Debt-Backlog, Sprint-Planung
Technische Erkennung allein reicht für nachhaltiges Deprecation Handling nicht aus, wenn die Ergebnisse nirgends landen. Bewährt hat sich ein zentrales Deprecation-Register: eine laufend aktualisierte Liste aller bekannten deprecated Fundstellen, ihrer Priorität und ihres Migrationsstatus. Dieses Register lässt sich direkt aus den Werkzeugen der vorherigen Abschnitte generieren, statt manuell gepflegt zu werden, was Inkonsistenzen zwischen Dokumentation und tatsächlichem Codestand vermeidet.
#!/usr/bin/env bash
# scan-deprecations.sh - Build a Deprecation Handling register from source and static analysis
set -euo pipefail
readonly MODULE_PATH="app/code/Mironsoft"
readonly REPORT_DIR="var/log/deprecation-report"
mkdir -p "$REPORT_DIR"
echo "[INFO] Scanning for @deprecated annotations..."
grep -rn "@deprecated" "$MODULE_PATH" --include="*.php" > "$REPORT_DIR/annotations.txt" || true
annotation_count=$(wc -l < "$REPORT_DIR/annotations.txt")
echo "[INFO] Found ${annotation_count} deprecated annotations in own module code"
echo "[INFO] Running PHPStan deprecation rules..."
bin/analyse "$MODULE_PATH" --level=5 --error-format=json > "$REPORT_DIR/phpstan.json" || true
echo "[INFO] Counting distinct deprecated call sites..."
jq '[.files[].messages[] | select(.message | test("deprecated"))] | length' "$REPORT_DIR/phpstan.json"
echo "[DONE] Deprecation register written to $REPORT_DIR"
Aus diesem Register entsteht der Tech-Debt-Backlog: pro Sprint wird ein fester Anteil der Kapazität, etwa zehn bis fünfzehn Prozent, für Deprecation-Handling-Tickets reserviert, statt es dem Zufall zu überlassen, ob Zeit übrig bleibt. Diese feste Reservierung verhindert, dass Deprecation Handling in Zeiten hoher Feature-Nachfrage vollständig verdrängt wird. In der Sprint-Planung werden die priorisierten Einträge aus dem Register als reguläre Tickets aufgenommen, inklusive Aufwandsschätzung und Verweis auf die betroffenen Dateien, damit die Migration denselben Qualitätsansprüchen unterliegt wie jede andere Codeänderung, inklusive Tests und Code-Review.
9. Praxisbeispiel: Migration einer konkreten deprecated Magento-Klasse
Ein alltägliches Beispiel für Deprecation Handling ist der direkte Aufruf von \Magento\Framework\App\ObjectManager::getInstance() innerhalb eines Konstruktors. Dieses Muster gilt als deprecated Anti-Pattern, weil es Dependency Injection umgeht und Abhängigkeiten verschleiert, die eigentlich über den Konstruktor sichtbar sein sollten. PHPStan mit den Magento-spezifischen Regeln meldet solche Aufrufe zuverlässig, weil sie sowohl gegen die Deprecation Rules als auch gegen grundlegende DI-Prinzipien verstoßen.
<?php
namespace Mironsoft\Catalog\Block;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\View\Element\Template;
class ProductBadge extends Template
{
protected $productRepository;
public function __construct(Template\Context $context, array $data = [])
{
parent::__construct($context, $data);
// Deprecated anti-pattern: bypasses constructor-based DI
$this->productRepository = ObjectManager::getInstance()->get(
\Magento\Catalog\Api\ProductRepositoryInterface::class
);
}
}
<?php
declare(strict_types=1);
namespace Mironsoft\Catalog\Block;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Framework\View\Element\Template;
final class ProductBadge extends Template
{
/**
* @param Template\Context $context Template context.
* @param ProductRepositoryInterface $productRepository Injected via DI instead of ObjectManager.
* @param array $data Additional block data.
*/
public function __construct(
Template\Context $context,
private readonly ProductRepositoryInterface $productRepository,
array $data = [],
) {
parent::__construct($context, $data);
}
}
Die Migration ersetzt den deprecated Aufruf durch eine reguläre Konstruktor-Injektion mit PHP-8.4-Constructor-Property-Promotion und einer readonly-Eigenschaft. Der Vorteil geht über das reine Beheben der PHPStan-Meldung hinaus: Die Abhängigkeit ist jetzt in der Klassensignatur sichtbar, in Unit-Tests problemlos mockbar und unterliegt der normalen DI-Konfiguration in di.xml. Genau solche kleinen, gut abgrenzbaren Migrationen sind der Kern von funktionierendem Deprecation Handling: technisch einfach, aber nur auffindbar, wenn Erkennung und Priorisierung wie in den vorherigen Abschnitten beschrieben etabliert sind.
10. Zusammenfassung
Deprecation Handling in Magento 2 ist kein Projekt mit Enddatum, sondern eine dauerhafte Praxis, die technische Werkzeuge und Team-Prozesse verbindet. PHPStan mit phpstan/phpstan-deprecation-rules erkennt deprecated Aufrufe zuverlässig im Aufruf-Graphen, eine Baseline trennt bekannte Altlasten von neuen Verstößen, und ein CI-Gate verhindert, dass neuer deprecated Code überhaupt erst gemerged wird. Composer-Audits und Marketplace-Hinweise ergänzen die Erkennung um Abhängigkeiten außerhalb des eigenen Codes.
Für die Migration selbst automatisiert Rector die mechanischen Teile, während Priorisierung nach Nutzungshäufigkeit und Nähe zur Entfernung dafür sorgt, dass die wirkungsvollsten Migrationen zuerst passieren. Ein Deprecation-Register und eine feste Kapazitätsreservierung im Sprint verankern Deprecation Handling strukturell im Team, statt es dem Zufall zu überlassen. Wer diese Bausteine kombiniert, kommt bei jedem künftigen Magento-Major-Update mit einer kleinen Restmenge statt einem unüberschaubaren Berg an deprecated Code an.
Deprecation Handling in Magento 2: Das Wichtigste auf einen Blick
Erkennung
phpstan/phpstan-deprecation-rules über bin/analyse erfasst den kompletten Aufruf-Graphen zuverlässig, ergänzt um Composer-Audits.
CI-Gate
Eine Pipeline-Stage mit bin/analyse und allow_failure: false blockiert neue Nutzung deprecated Codes vor dem Merge.
Migration
Rector automatisiert mechanische Umschreibungen, Plugin- statt Preference-Migration reduziert zusätzlich stille Deprecation-Kandidaten.
Prozess
Deprecation-Register plus feste Sprint-Kapazität verankern Deprecation Handling dauerhaft statt als Einmalprojekt.
11. FAQ: Deprecation Handling in Magento 2
1Was bedeutet Deprecation Handling in Magento konkret?
2Woran erkenne ich eine deprecated Klasse?
3Welches PHPStan-Level brauche ich?
4Übernimmt Rector die Migration vollständig?
5Unterschied zu einem Versions-Upgrade?
6Wie priorisiere ich deprecated APIs?
7Wie erzwinge ich Deprecation Handling in CI?
8Was tun bei deprecated Marketplace-Modulen?
9Wie dokumentiere ich Deprecation Handling?
10Was passiert bei Ignorieren von deprecated Code?
Mironsoft
Deprecation Handling, Rector-Migrationen und CI-Pipelines für Magento 2
Wie viel deprecated Code steckt in eurer Magento-Installation?
Wir scannen euren Codebestand mit PHPStan, priorisieren die Funde nach Risiko und richten ein Deprecation Handling ein, das kontinuierlich läuft, statt bei jedem Upgrade neu anzufangen.
Deprecation-Audit
Vollständiger PHPStan-Scan des Codebestands inklusive Composer-Abhängigkeiten und Priorisierung nach Risiko
Migrations-Service
Automatisiertes Refactoring mit Rector kombiniert mit manueller Migration komplexer Preference-zu-Plugin-Fälle
CI-Pipeline-Einrichtung
Automatisierte Deprecation-Gates in GitLab CI, die neue Nutzung deprecated Codes vor dem Merge blockieren