Che cosa è più performante: entity_metadata_wrapper o field_get_items?


10

Per ottenere valori dalle entità, ci sono due modi:

  • Usa field_get_itemse ottieni il valore di un campo
  • Usa entity_metadata_wrappere ottieni il valore di un campo

Sebbene entity_metadata_wrapperelimini le differenze linguistiche, la sua API a volte è ancora imbarazzante, specialmente quando si utilizza PHP 5.3. Ad esempio, ottenere il valore di un campo di testo lungo di solito procede in questo modo:

$field = $wrapper->field->value();
print $field['safe_value'];

Fortunatamente, PHP 5.4 supporta questa sintassi: print $wrapper->field->value()['safe_value'];.

Ma la mia domanda è più preoccupata per le prestazioni. Come funzionano entrambi? Interrogano il database ogni volta che richiedono un valore? Richieste entity_metadata_wrappertutto in una volta? (Rendere field_get_itempiù adatto ai recuperi a valore singolo.)

Non sono abbastanza coraggioso da immergermi in profondità nella fonte Drupal.


1
field_view_field()è per il rendering di un campo. La funzione per ottenere il valore di un campo è field_get_items () .
kiamlaluno

E field_get_items()comporta un sovraccarico del database pari a zero, quindi penso che sia un caso piuttosto aperto e chiuso :)
Clive

@Clive come mai si verifica field_get_items()un sovraccarico del database zero? Deve ottenere i suoi dati da qualche parte, giusto?
Florian Margaine,

Inoltre, sono davvero interessato a sapere come entity_metadata_wrapperfunziona, dal punto di vista delle prestazioni.
Florian Margaine,

2
Si passa un oggetto entità completamente caricato in field_get_items()modo che l'overhead sia già stato sostenuto ... è un po 'un percorso strangolato in D7 per essere onesti
Clive

Risposte:


12

La risposta breve: field_get_items () è più performante di entity_metadata_wrapper ().

Controlla il codice per queste funzioni:

Entrambi richiedono il passaggio lungo l'entità, che è già stata caricata dal database . Per esempio:

$node = node_load(123);
$items = field_get_items('node', $node, 'field_my_field_name');
print $items[0]['value'];

o, come hai già suggerito:

$wrapper = entity_metadata_wrapper('node', $node);
$field = $wrapper->field_my_field_name->value();
print $field['safe_value'];

Entrambi questi casi mi danno fastidio a causa della logica sciocca nel cercare di ottenere un valore che è già disponibile per te, ma sono sicuramente utili in molti casi.

Potresti semplicemente farlo, print $node->field_my_field_name[LANGUAGE_NONE][0]['value'];ma ciò genererebbe errori di avviso PHP se il campo non ha un valore, poiché stai cercando di accedere ad array che potrebbero non esistere (ad es [LANGUAGE_NONE][0]['value'].). Mi ritrovo a farlo abbastanza spesso ultimamente:

if ($field = field_get_items('node', $node, 'field_my_field_name')) {
  print $field[0]['value'];
}

che è molto più pulito del fare:

if (isset($node->field_my_field_name[LANGUAGE_NONE]) && isset($node->field_my_field_name[LANGUAGE_NONE][0])) {
  print $node->field_my_field_name[LANGUAGE_NONE][0]['value'];
}

Se guardi il codice field_get_items()), noterai che non sta facendo altro, assicurandoti che l'array del campo contenga dati nella lingua corrente e quindi li restituisca. Quindi, il sovraccarico di eseguire una funzione così piccola è trascurabile, ma se sei davvero interessato alle prestazioni puoi semplicemente fare il tuo controllo se i dati esistono e quindi stamparli.

Modifica: dato che le field_get_items()esecuzioni field_language()avrebbero effettivamente un impatto sulle prestazioni maggiore rispetto al semplice controllo della lingua, quindi, se sai già che esiste $ language-> language, potresti semplicemente scrivere la tua funzione super performante:

function my_super_performant_field_value_getter($entity, $field_name) {
  return isset($entity->{$field_name}[{$entity->language}]) ? $entity->{$field_name}[{$entity->language}] : FALSE;
}

Ok, quindi a parte questi controlli, l'entità viene caricata una volta, non importa quante volte li uso? Anche se utilizzo i riferimenti alle entità?
Florian Margaine,

Sì, questa è in realtà una caratteristica piuttosto interessante dell'API di entità in D7. Una volta caricata un'entità, questa viene memorizzata nella cache per la durata di tale richiesta. Quindi, se lo fai $node = node_load(123);in uno script e lo fai di nuovo altrove, non incorri nell'overhead delle prestazioni di un carico e di una compilazione di oggetti completi: Drupal assegna a quella variabile una copia dell'entità esistente. Se si desidera caricare una nuova copia, è necessario passare $reset = TRUEalla funzione di caricamento dell'entità. Inoltre, guarda le mie modifiche riguardanti un getter super performante.
Charlie Schliesser,

1
if (isset($node->field_my_field_name[LANGUAGE_NONE]) && isset($node->field_my_field_name[LANGUAGE_NONE][0])) {non è necessario, isset($node->field_my_field_name[LANGUAGE_NONE][0]è abbastanza.

@chx Sono d'accordo, ma non lo sarebbe isset($node->field_my_field_name[LANGUAGE_NONE]), dal momento che la lingua non verrà impostata su un campo vuoto? Penso che sia il delta / [0]che sia ridondante.
Charlie Schliesser,

1
@GilesB, più query sul database spesso non sono migliori dei join. Il caricamento desideroso è una tecnica di ottimizzazione. Ma anche dicendo questo, penso che il tuo presupposto sia falso e EntityMetadataWrapper è probabilmente più lento, ma è molto più bello da usare. Anche questa è una micro ottimizzazione che OP non deve pensare quando si lavora con Drupal.
Nicholas Ruunu,
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.