Magento 2 - dobra praktyka używania / unikania magicznych pobudzaczy?


21

Magiczne pobieracze na Varien_Object(M1) i DataObject(M2) są powszechną praktyką, ale w Magento 2 korzystanie z nich jest niewłaściwe.

Dobry:

  • łatwy do odczytu / zapisu

Zły

Pytanie

W Magento 2 mamy dwie nowe metody:

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

Czy jest jakiś dobry powód, aby nadal używać getData($key)lub magicznych pobieraczy?


Edytować:

@Vinai dzięki. Nie wspomniałem o @methodmetodzie, ponieważ moje podejście było zupełnie inne.

Pomaga tylko IDE, ale nie ma wpływu na inne rzeczy.

Istnieje kilka scalonych PR, które są „mikrooptymalizacjami”, takimi jak rzutowanie na (int)zamiast intval()lub uzyskanie rozmiaru tablicy poza pętlami (nawet dla małych tablic).

Z drugiej strony są

  1. magiczne pobieracze, które mają pewne „narzuty”, jak opisał Marius…

    strtolower(trim(preg_replace('/([A-Z]|[0-9]+)/', "_$1", $name), '_'));
  2. getData($key) mehtods muszą także wykonać 2-3 dodatkowe kontrole ...

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

W przypadku własnego kodu całkowicie zgadzam się na preferowanie prawdziwych metod, ale w tych samych przypadkach nie jest to możliwe ... np. Utworzyłeś niestandardowe zdarzenie ...

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

Używanie 3. z /** @var some $value */wydaje mi się najlepsze. (?)


1
Możesz dodać metody do bloku doc ​​klas, aby narzędzia do analizy kodu nie narzekały na nieistniejące metody. Uważam też, że używanie cyfr w klawiszach samo w sobie jest złą praktyką, więc nie powinno być tutaj wymieniane jako „Złe”.
Lily Bergonzat

Odpowiedzi:


20

Powyższe pytanie dotyczy użycia magicznych metod w porównaniu z getDataByKeylub getDataByPath. Myślę, że jest też trzecia opcja, a mianowicie wdrożenie metod getter i setter.

Wszystkie getData*metody mają tę wadę, że muszą być opatrzone adnotacjami, aby wnioskowanie typu działało.
Zwykle robi się to z /* @var string $foo */adnotacją nad getData*połączeniem.
Jest to nieco śmierdzące, ponieważ typ danych powinien być zadeklarowany w klasie, która zawiera dane, a nie w klasie, która wywołuje getData*.
Powodem tego jest to, że jeśli dane się zmienią, klasa najprawdopodobniej zostanie zaktualizowana, nie wszystkie getData*witryny wywołujące.
Dlatego uważam, że prawdziwe metody zwiększają łatwość konserwacji w porównaniu do korzystania z getData*akcesoriów.

Myślę więc, że sprowadza się to do kompromisu między łatwością konserwacji i szybszą implementacją (mniej kodu do napisania).

Na szczęście w dzisiejszych czasach IDE są naprawdę dobre w tworzeniu dla nas implementacji gettera i settera, więc ten argument tak naprawdę nie ma już zastosowania.

Kolejnym argumentem przeciwko magicznym modułom pobierającym i ustawiającym, którego brakuje w powyższym pytaniu, jest to, że nie można dla nich tworzyć wtyczek.

Jedyną inną wartością, którą, jak sądzę, mogę dodać do tematu, jest próba zebrania powodów użycia lub @methodnieużytkowania adnotacji, jeśli z jakiegoś powodu nie ma mowy o zastosowaniu prawdziwych metod.

Plusy

  • @methodAdnotacja jest trochę mniej kodu do zapisu w porównaniu do realizacji prawdziwego getter i setter. Nie jest to jednak do końca prawdą, ponieważ IDE są dobre w generowaniu metod akcesorów, więc nie jest to już prawdziwą korzyścią.

Cons

  • Łatwo jest, żeby coś poszło nie tak.
    • Adnotacje są komentarzami, łatwo stają się przestarzałe, gdy kod ewoluuje, ale adnotacje nie są aktualizowane. Prawdziwe metody są bardziej niezawodne.
    • Możliwe jest dodawanie wielu adnotacji z różnymi typami podpisów bez błędu interpretera - zachowanie statycznej analizy kodu jest niezdefiniowane i może prowadzić do subtelnych błędów, które są trudne do wyśledzenia.
    • Jeśli istnieją zarówno @methodadnotacja, jak i prawdziwa metoda o tej samej nazwie, podpis typu adnotacji zastępuje prawdziwą metodę podczas analizy kodu statycznego, co jest przeciwieństwem działania interpretera PHP. To znowu może łatwo prowadzić do subtelnych błędów.

Z powyższych powodów osobiście nie używam @methodadnotacji, jeśli mogę ich uniknąć.
Dla kodu, który ma długo żyć, implementuję metody getter i setter. Zwiększenie łatwości konserwacji jest warte wysiłku, aby uruchomić IDE w celu ich wygenerowania.

Aby uzyskać bardziej eksperymentalny kod podczas piku lub prosty szczegół implementacji modułu, używam również getData*metod, ponieważ jestem leniwy.


Ładne podsumowanie. Dziękuję Vinai. To odpowiada więcej niż o to prosiłem.
sv3n

1

Wszystkie getData*metody mają tę wadę, że muszą być opatrzone adnotacjami, aby wnioskowanie typu działało.

Zwykle robi się to z /*@var string $foo */adnotacją nad getData*połączeniem. Jest to nieco śmierdzące, ponieważ typ danych powinien zostać zadeklarowany w klasie zawierającej dane, a nie w klasie, która wywołuje getData *.

Powodem tego jest to, że jeśli dane się zmienią, klasa najprawdopodobniej zostanie zaktualizowana, nie wszystkie getData*witryny wywołujące. Dlatego uważam, że rzeczywiste metody zwiększają łatwość konserwacji w porównaniu do korzystania z akcesoriów getData *.

Tak, śmierdzi, ale można (i należy?) Tego uniknąć. Myślę, że jest to bardzo popularny kod i często sugerowany:

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

Problem polega na tym, że zgadujesz, że zwracana wartość jest typu Fooz wywoływaną getId()metodą.

Jeśli chodzi o łatwość konserwacji, dlaczego nie założyć typu zmiennej i dodać InvalidArgumentException?

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

To również naprawia analizę kodu statycznego w przypadku, gdy $model->getProduct()ma różne typy zwracanych danych - jak Foo|false. W pierwszym przypadku narzekałby doSomething()na możliwość wezwania false.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.