Magento 2 - gute Praxis, um magische Getter zu verwenden / zu vermeiden?


21

Magic Getter auf Varien_Object(M1) und DataObject(M2) sind gängige Praxis, aber mit Magento 2 fühlt es sich falsch an, es zu verwenden.

Gut:

  • leicht zu lesen / schreiben

Schlecht

Frage

Mit Magento 2 haben wir zwei neue Methoden:

  • getDataByKey($key)
  • getDataByPath($path)

Gibt es noch einen guten Grund für den Einsatz getData($key)oder irgendwelche Zauberkünstler?


Bearbeiten:

@ Vinai danke. Ich habe die @methodMethode nicht erwähnt , weil mein Ansatz ganz anders war.

Es hilft nur der IDE, hat aber keinen Einfluss auf andere Dinge.

Es gibt mehrere mergedf PRs auf, die „Mikro-Optimierungen“ wie Gießen (int)statt intval()oder Array - Größe außerhalb Schleifen (auch für kleine Arrays) erhalten.

Auf der anderen Seite gibt es

  1. magische Getter, die etwas "Overhead" haben, wie Marius es beschrieben hat ....

    strtolower(trim(preg_replace('/([A-Z]|[0-9]+)/', "_$1", $name), '_'));
  2. getData($key) Mehtods müssen auch 2-3 zusätzliche Prüfungen ...

    • if ('' === $key) {
    • if (strpos($key, '/')) {
    • if ($index !== null) {

Für eigenen Code ist es völlig einverstanden, echte Methoden zu bevorzugen, aber in den gleichen Fällen ist dies möglicherweise nicht der Fall ... Sie haben z. B. ein benutzerdefiniertes Ereignis erstellt ...

$value = $observer->getVar_1();
$value = $observer->getData('var_1');
$value = $observer->getDataByKey('var_1');

3. mit /** @var some $value */scheinen mir am besten. (?)


1
Sie können die Methoden im Class-Doc-Block hinzufügen, damit sich die Codeanalyse-Tools nicht über nicht vorhandene Methoden beschweren. Ich denke auch, dass die Verwendung von Ziffern in Schlüsseln selbst eine schlechte Praxis ist, daher sollte sie hier imo nicht als "Schlecht" aufgeführt werden.
Lily Bergonzat

Antworten:


20

Bei der obigen Frage geht es um die Verwendung magischer Methoden im Vergleich zu getDataByKeyoder getDataByPath. Ich denke, es gibt auch eine dritte Option, nämlich die Implementierung echter Get- und Setter-Methoden.

Die getData*Methoden haben alle den Nachteil, dass sie mit Anmerkungen versehen werden müssen, damit die Typinferenz funktioniert.
In der Regel erfolgt dies mit einer /* @var string $foo */Anmerkung über dem getData*Aufruf.
Dies ist etwas stinkend, da der Datentyp in der Klasse deklariert werden sollte, die die Daten enthält, nicht in der Klasse, die aufruft getData*.
Der Grund dafür ist, dass bei einer Änderung der Daten die Aktualisierung der Klasse am wahrscheinlichsten ist und nicht aller getData*Aufrufsites.
Deshalb glaube ich, dass echte Methoden die Wartbarkeit im Vergleich zur Verwendung von getData*Accessoren verbessern.

Ich denke, es läuft auf einen Kompromiss zwischen Wartbarkeit und schnellerer Implementierung hinaus (weniger Code zum Schreiben).

Glücklicherweise sind IDEs heutzutage wirklich gut darin, die Get- und Setter-Implementierungen für uns zu erstellen, sodass dieses Argument nicht mehr wirklich zutrifft.

Ein weiteres Argument gegen Magic Getter und Setter, das in der obigen Frage fehlt, ist, dass es nicht möglich ist, Plugins für sie zu erstellen.

Der einzige andere Wert, den ich dem Thema hinzufügen kann, ist der Versuch, die Gründe für die Verwendung oder Nichtverwendung von @methodAnmerkungen zu sammeln , wenn die Implementierung realer Methoden aus irgendeinem Grund nicht in Frage kommt.

Vorteile

  • Eine @methodAnnotation ist etwas weniger zu schreibender Code als die Implementierung eines echten Get- und Setters. Heutzutage ist dies jedoch kaum mehr der Fall, da IDEs gut darin sind, Zugriffsmethoden zu generieren. Dies ist also kein wirklicher Vorteil mehr.

Nachteile

  • Es ist leicht, dass etwas schief geht.
    • Anmerkungen sind Kommentare. Sie werden leicht hinfällig, wenn sich der Code weiterentwickelt, aber die Anmerkungen werden nicht aktualisiert. Reale Methoden sind robuster.
    • Es ist möglich, mehrere Annotationen mit unterschiedlichen Typensignaturen hinzuzufügen, ohne dass ein Interpreterfehler auftritt. Das Verhalten der statischen Codeanalyse ist nicht definiert und kann zu subtilen Fehlern führen, die nur schwer aufzuspüren sind.
    • Wenn sowohl eine @methodAnnotation als auch eine reale Methode mit demselben Namen vorhanden sind, überschreibt die Signatur des Annotationstyps die reale Methode bei der statischen Code-Analyse. Dies ist das Gegenteil von dem, was der PHP-Interpreter tut. Dies kann wiederum leicht zu subtilen Fehlern führen.

Aus den oben genannten Gründen verwende ich persönlich keine @methodAnmerkungen, wenn ich sie vermeiden kann.
Für Code, der lange leben soll, implementiere ich echte Getter- und Setter-Methoden. Der Gewinn an Wartbarkeit ist die Anstrengung wert, die IDE auszulösen, um sie zu generieren.

Für mehr experimentellen Code während eines Spikes oder für ein einfaches Implementierungsdetail eines Moduls verwende ich auch getData*Methoden, weil ich faul bin.


Schöne Zusammenfassung. Vielen Dank, Vinai. Das beantwortet mehr als ich eigentlich gefragt habe.
SV3N

1

Die getData*Methoden haben alle den Nachteil, dass sie mit Anmerkungen versehen werden müssen, damit die Typinferenz funktioniert.

In der Regel erfolgt dies mit einer /*@var string $foo */Anmerkung über dem getData*Aufruf. Dies ist etwas unangenehm, da der Datentyp in der Klasse deklariert werden sollte, die die Daten enthält, nicht in der Klasse, die getData * aufruft.

Der Grund dafür ist, dass bei einer Änderung der Daten die Aktualisierung der Klasse am wahrscheinlichsten ist und nicht aller getData*Aufrufsites. Deshalb glaube ich, dass echte Methoden die Wartbarkeit im Vergleich zur Verwendung von getData * -Zugriffsmethoden verbessern.

Ja, es riecht, aber kann (und sollte?) Vermieden werden. Ich denke, das ist sehr allgemeiner Code und wird oft vorgeschlagen:

/** @var Foo $product */
$product = $model->getProduct()
if ($product->getId()) {
    $product->doSomething();
}

Das Problem ist, dass Sie nur vermuten, dass der Rückgabewert vom Typ Foomit einer aufrufbaren getId()Methode ist.

Nehmen Sie aus Gründen der Wartbarkeit einen Variablentyp an und fügen Sie einen hinzu InvalidArgumentException.

$product = $model->getProduct()
if ($product instanceof Foo && $product->getId()) {
    $product->doSomething();
}

Dies behebt auch die statische Code-Analyse für den Fall, dass $model->getProduct()unterschiedliche Rückgabetypen vorliegen Foo|false. Im ersten Fall würde er sich über einen doSomething()eventuellen Rückruf beschweren false.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.