Konvertierung von PHP Klassen Annotationen in PHP-Attribute
Seit Jahren stützte sich Drupal auf die Bibliothek doctrine/annotations, um Plugin-Klassen mit Metadaten zu versehen. Dieser Ansatz funktioniert über Docblock-Kommentare – die /** ... */-Blöcke, die oberhalb von Klassendefinitionen angelegt sind. So praktisch diese Methode auch ist, hat sie mehrere Einschränkungen und wird in Zukunft durch PHP Attributes ersetzt werden.
In diesem Blogbeitrag werden die Änderungen anhand des bekannten migrate_plus Moduls näher beschrieben.
Die Veröffentlichung der Version 6.0.9 des Drupal-Moduls migrate_plus führte eine bedeutende Breaking Change ein, die Entwickler betrifft, die benutzerdefinierte Migrations-Plugins pflegen: Das Modul verlangt nun, dass Plugins PHP-Attribute anstelle der älteren Doctrine-Annotationssyntax verwenden. Die Änderung wurde leider ohne Hinblick der Abwärtskompatibilität eingeführt und führt dazu, dass bestehende migrate_plus Plugins nicht mehr funktionieren.
Diese Umstellung ist nicht auf migrate_plus beschränkt, sondern spiegelt eine breitere Bewegung im gesamten Drupal-Ökosystem wider, Plugin-Definitionen mithilfe nativer Sprachfunktionen von PHP 8.1+ darzustellen.
Warum ist eine Umstellung auf PHP Attribute sinnvoll?
Bevor wir in die technische Umsetzung betrachten, ist es wichtig zu verstehen, warum dieser Breaking Change existiert und welches Problem es lösen soll.
Die Probleme mit Doctrine-Annotationen
Seit Jahren stützte sich Drupal auf die Bibliothek doctrine/annotations, um Plugin-Klassen mit Metadaten zu versehen. Dieser Ansatz funktioniert über Docblock-Kommentare – die /** ... */-Blöcke, die oberhalb von Klassendefinitionen angelegt sind. So praktisch diese Methode auch ist, hat sie mehrere Einschränkungen:
- Performance overhead. Annotationen werden zur Laufzeit interpretiert. Der zusätzliche Parsing-Schritt fügt während der Plugin-Erkennung Overhead hinzu, den Drupal zwar durch Caching abmildert, aber nicht vollständig beseitigen kann. Für große Sites mit vielen Plugins kann dies spürbare Auswirkungen haben.
- Fehleranfällige Syntax. Da Annotationen in Kommentaren existieren, sind sie anfällig für einfache Formatierungsfehler. Diese Fehler sind schwer zu debuggen, da sie zur Laufzeit auftreten und nicht während der statischen Analyse.
- Wartungsaufwand. Die Bibliothek doctrine/annotations wird nicht mehr aktiv gepflegt und wurde von ihren Maintainers als veraltet eingestuft.
- Begrenzte IDE-Integration. Da Annotationen in Kommentaren statt im Code stehen, können IDEs dafür nativ keine Autovervollständigung, Typ-Hinweise oder Navigationsfunktionen bereitstellen.
PHP-Attribute: Die Lösung des Problems
PHP 8.0 führte native Attribute ein. Damit wird ein Sprachfeature beschrieben, das speziell zur Lösung des Metadatenproblems entwickelt wurde. Während der anfänglichen Implementierung von PHP 8.0 die Unterstützung für verschachtelte Attribute fehlte (die für die komplexen Plugin-Metadaten von Drupal unerlässlich sind), fügte PHP 8.1 diese Fähigkeit hinzu und machte Attribute damit für die Anforderungen von Drupal nutzbar.
Attribute bieten mehrere Vorteile gegenüber Annotationen::
- Verarbeitung zur Zeit der Kompilierung. PHP verarbeitet Attribute während der Kompilierung, nicht zur Laufzeit. Dadurch entfällt der Parsing-Overhead vollständig und die Plugin-Erkennung wird schneller.
- Typsicherheit und Validierung. Da Attribute Teil der PHP-Sprache selbst sind, unterliegen sie derselben Validierung wie regulärer Code. Ungültige Syntax wird sofort erkannt und nicht erst später zur Laufzeit entdeckt.
- IDE-Unterstützung. Moderne IDEs erkennen Attribute als native Sprachkonstrukte und bieten vollständige Autovervollständigung, Type-Hinting und Code-Navigation.
- Klare Semantik. Die Verwendung der Syntax #[AttributeName] macht Metadaten eindeutig von Dokumentationskommentaren unterscheidbar. Der Code ist besser lesbar und wartbarer.
- Zukunftssicher. Während sich PHP weiterentwickelt, werden Attribute Teil dieser Entwicklung sein. Drupal wird somit nicht von einer Third-Party Bibliothek abhängig sein.
Step-by-Step Umstellung für migrate_plus
Als Beispiel für die Konvertierung nehmen wir ein einfaches migrate_plus-Plugin und zeigen, was geändert werden muss.
Step 1: Benutzerdefinierte migrate_plus-Plugins lokalisieren
Das migrate_plus Modul unterstützt die folgenden Plugintypen.
your_module/
├── src/
│ └── Plugin/
│ └── migrate_plus/
│ ├── data_parser/ (data parser plugins)
│ └── data_fetcher/ (data_fetcher plugins)
│ └── authentication/ (authentication plugins)Step 2: use Statements hinzufügen
Für unser Beispiel nehmen wir ein data_parser-Plugin. Hier müssen wir die nötigen use Statements hinzufügen.
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\migrate_plus\Attribute\DataParser;Step 3: Annotations in Attribute umwandeln
Docblock-Annotation entfernen und durch Attribut-Deklarationen ersetzen.
Vorher
/**
* Data parser plugin description.
*
* @DataParser(
* id = "my_data_parser_plugin_id",
* title = @Translation("My custom data parser plugin")
* )
*/
class MyDataParserPlugin implements DataParserPluginInterface {
// Plugin code.
}Nachher
/**
* Data parser plugin description.
*/
#[DataParser(
id: 'my_data_parser_plugin_id',
title: new TranslatableMarkup('My custom data parser plugin')
)]
class MyDataParserPlugin implements DataParserPluginInterface {
// Plugin code.
}Wesentliche Änderungen:
- Attributdefinitionen aus den Doctrine Annotations extrahieren
- Nutzung von id: anstelle von id =
- Änderung von "string" in 'string'
Step 4: Testen und überprüfen
Nachdem die Plugins entsprechend angepasst wurden, muss der Drupal Cache einmal neu aufgebaut werden.
drush cache:rebuildIm Anschluss kann geprüft werden, ob die Plugins wieder korrekt erkannt werden.
drush migrate:statusDies sollte keine Fehler verursachen und die Migration sollte ohne Probleme ausgeführt werden können.
Besonderheiten bei Update auf migrate_plus 6.0.9
Die Version 6.0.9 migrate_plus module bringt als Neuerung die Umstellung auf PHP Attributes mit sich ( d.o/3541220).
- Abwärtskompatibilität ist nicht gegeben. Anders als beim schrittweisen Übergang im Drupal-Core, bei dem Annotationen und Attribute koexistieren, erfordert migrate_plus 6.0.9, dass Plugins Attribute verwenden. Alte Plugins, die noch auf Doctrine Annotations basieren werden nicht erkannt und verursachen Fehler.
- Betreffende Plugins müssen aktualisiert werden. Wenn bestehende Migration auf benutzerdefinierten Plugintypen basieren, müssen diese konvertiert werden. Ein migrate_plus Plugin kann keine Doctrine Annotation und PHP Attributes mischen.
- Der Breaking Change betrifft Contrib und Custom-Module. Alle Contrib oder benutzerdefinierten Module, die Migrations-Plugins bereitstellen, müssen aktualisiert werden.
Weitere Quellen: