Magento 2 - buone pratiche per usare / evitare i getter magici?


21

I getter magici su Varien_Object(M1) e DataObject(M2) sono una pratica comune, ma con Magento 2 sembra sbagliato usarlo.

Buona:

  • facile da leggere / scrivere

Cattivo

Domanda

Con Magento 2 abbiamo due nuovi metodi:

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

C'è qualche buona ragione per usare ancora getData($key)o qualche getter magico?


Modificare:

@Vinai grazie. Non ho menzionato il @methodmetodo, perché il mio approccio era piuttosto diverso.

Aiuta solo l'IDE, ma non ha alcun impatto su altre cose.

Esistono diverse PR unite che sono "micro-ottimizzazioni" come il casting (int)invece di intval()o ottenere dimensioni di array all'esterno di loop (anche per array di piccole dimensioni).

D'altra parte ci sono

  1. getter magici, che hanno un po 'di "sovraccarico" come descritto da Marius ....

    strtolower(trim(preg_replace('/([A-Z]|[0-9]+)/', "_$1", $name), '_'));
  2. getData($key) i mehtod devono anche 2-3 ulteriori controlli ...

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

Per il proprio codice è assolutamente d'accordo di preferire metodi reali, ma negli stessi casi non è possibile ... ad esempio, hai creato un evento personalizzato ...

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

Usando 3rd with /** @var some $value */mi sembra meglio. (?)


1
È possibile aggiungere i metodi nel blocco doc della classe, in modo che gli strumenti di analisi del codice non si lamentino dei metodi inesistenti. Inoltre penso che usare le cifre nei tasti sia di per sé una cattiva pratica, quindi non dovrei essere elencato come "Cattivo" qui.
Lily Bergonzat,

Risposte:


20

La domanda sopra riguarda l'uso dei metodi magici rispetto a getDataByKeyo getDataByPath. Penso che ci sia anche una terza opzione, che sta implementando metodi di getter e setter reali.

Tutti i getData*metodi hanno il rovescio della medaglia che devono essere annotati affinché l'inferenza di tipo funzioni.
Di solito ciò viene fatto con /* @var string $foo */un'annotazione sopra la getData*chiamata.
Questo è un po 'puzzolente, perché il tipo di dati deve essere dichiarato nella classe che contiene i dati, non nella classe che chiama getData*.
Il motivo è che se i dati cambiano, è più probabile che la classe venga aggiornata, non tutti i getData*siti di chiamata.
Ecco perché penso che i metodi reali aumentino la manutenibilità rispetto all'utilizzo di getData*accessori.

Quindi penso che si riduca a un compromesso tra manutenibilità e implementazione più rapida (meno codice da scrivere).

Fortunatamente, al giorno d'oggi gli IDE sono davvero bravi a creare le implementazioni getter e setter per noi, quindi tale argomento non si applica più.

Un altro argomento contro maghi e setter magici che manca alla domanda sopra è che non è possibile creare plugin per loro.

L'unico altro valore che penso di poter aggiungere all'argomento è cercare di raccogliere i motivi per utilizzare o meno le @methodannotazioni, se l'implementazione di metodi reali è fuori discussione per qualche motivo.

Professionisti

  • @methodUn'annotazione è un po 'meno codice di scrittura rispetto ad eseguire una vera getter e setter. Questo è quasi vero anche se al giorno d'oggi perché gli IDE sono bravi a generare metodi di accesso, quindi non è più un vero vantaggio.

Contro

  • È facile che le cose vadano male.
    • Le annotazioni sono commenti, diventano facilmente obsolete quando il codice si evolve ma le annotazioni non vengono aggiornate. I metodi reali sono più robusti.
    • È possibile aggiungere più annotazioni con firme di tipo diverso senza un errore dell'interprete - il comportamento dell'analisi del codice statico non è definito e può portare a bug sottili che sono difficili da rintracciare.
    • Se @methodesistono sia un'annotazione che un metodo reale con lo stesso nome, la firma del tipo di annotazione sovrascrive il metodo reale durante l'analisi del codice statico, che è l'opposto di quello dell'interprete PHP. Questo di nuovo può facilmente portare a bug sottili.

Per i motivi di cui sopra, personalmente non utilizzo le @methodannotazioni se posso evitarle.
Per il codice destinato a durare a lungo, implemento metodi di getter e setter reali. Il guadagno di manutenibilità vale lo sforzo di innescare l'IDE per generarli.

Per un codice più sperimentale durante uno spike, o per un semplice dettaglio di implementazione di un modulo, uso anche i getData*metodi, perché sono pigro.


Bel riassunto. Grazie Vinai. Questo risponde più di quello che ho effettivamente chiesto.
sv3n

1

Tutti i getData*metodi hanno il rovescio della medaglia che devono essere annotati affinché l'inferenza di tipo funzioni.

Di solito ciò viene fatto con /*@var string $foo */un'annotazione sopra la getData*chiamata. Questo è un po 'maleodorante, perché il tipo di dati deve essere dichiarato nella classe che contiene i dati, non nella classe che chiama getData *.

Il motivo è che se i dati cambiano, è più probabile che la classe venga aggiornata, non tutti i getData*siti di chiamata. Ecco perché penso che i metodi reali aumentino la manutenibilità rispetto all'utilizzo degli accessori getData *.

Sì, è maleodorante, ma può (e dovrebbe?) Essere evitato. Penso che questo sia un codice molto comune e spesso suggerito:

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

Il problema è solo indovinare che il valore restituito è di tipo Foocon un getId()metodo richiamabile .

Per manutenibilità, perché non assumere un tipo variabile e aggiungere un InvalidArgumentException?

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

Questo risolve anche l'analisi del codice statico nel caso in cui $model->getProduct()abbia diversi tipi di ritorno - come Foo|false. Nel primo caso si lamenterebbe di doSomething()poter chiedere di essere possibile false.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.