Was ist performanter: entity_metadata_wrapper oder field_get_items?

10

Es gibt zwei Möglichkeiten, um Werte von Entitäten abzurufen:

  • Verwenden Sie field_get_itemsund erhalten Sie den Wert eines Feldes
  • Verwenden Sie entity_metadata_wrapperund erhalten Sie den Wert eines Feldes

Obwohl entity_metadata_wrapperdie Sprachunterschiede abstrahiert werden, ist die API manchmal immer noch umständlich, insbesondere bei Verwendung von PHP 5.3. Wenn Sie beispielsweise den Wert eines Langtextfelds abrufen, gehen Sie normalerweise folgendermaßen vor:

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

Glücklicherweise unterstützt PHP 5.4 diese Syntax : print $wrapper->field->value()['safe_value'];.

Aber meine Frage ist mehr über die Leistung besorgt. Wie arbeiten beide? Fragen sie die Datenbank jedes Mal ab, wenn sie einen Wert anfordern? Fordert entity_metadata_wrapperalles auf einmal an? (Besser field_get_itemgeeignet für Einzelwertabfragen.)

Ich bin nicht mutig genug, tief in die Drupal-Quelle einzutauchen.

Florian Margaine
quelle
1
field_view_field()dient zum Rendern eines Feldes. Die Funktion zum Abrufen des Werts eines Feldes lautet field_get_items () .
Kiamlaluno
Und field_get_items()verursacht keinen Datenbank-Overhead, also denke ich, dass dies ein ziemlich offener und geschlossener Fall ist :)
Clive
@Clive Wie kommt es, dass field_get_items()kein Datenbank-Overhead entsteht? Es muss seine Daten irgendwo bekommen, oder?
Florian Margaine
Außerdem bin ich sehr daran interessiert zu wissen, wie entity_metadata_wrapperdie Leistung funktioniert.
Florian Margaine
2
Sie übergeben ein vollständig geladenes Entitätsobjekt, field_get_items()sodass der Overhead bereits angefallen ist ... um ehrlich zu sein, ist es in D7 eine etwas erdrosselte Route
Clive

Antworten:

12

Die kurze Antwort: field_get_items () ist performanter als entity_metadata_wrapper ().

Überprüfen Sie den Code für diese Funktionen:

Für beide ist es erforderlich, dass Sie die Entität weitergeben, die bereits aus der Datenbank geladen wurde . Beispielsweise:

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

oder, wie Sie bereits vorgeschlagen haben:

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

Diese beiden Fälle stören mich irgendwie wegen der dummen Logik beim Versuch, einen Wert zu erhalten, der Ihnen bereits zur Verfügung steht, aber sie sind sicherlich in vielen Fällen nützlich.

Sie könnten dies einfach tun, print $node->field_my_field_name[LANGUAGE_NONE][0]['value'];aber das würde PHP-Benachrichtigungsfehler auslösen, wenn das Feld keinen Wert hat, da Sie versuchen, auf Arrays zuzugreifen, die möglicherweise nicht vorhanden sind (dh [LANGUAGE_NONE][0]['value']). Ich mache das in letzter Zeit ziemlich oft:

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

Das ist viel sauberer als zu tun:

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'];
}

Wenn Sie sich den Code field_get_items())ansehen, werden Sie feststellen, dass er nichts weiter tut, als sicherzustellen, dass das Array des Felds Daten in der aktuellen Sprache enthält, und diese dann zurückgibt. Der Aufwand für die Ausführung einer so kleinen Funktion ist also vernachlässigbar. Wenn Sie sich jedoch wirklich mit der Leistung befassen, können Sie einfach selbst prüfen, ob die Daten vorhanden sind, und sie dann ausdrucken.

Bearbeiten: Da field_get_items()Läufe field_language()tatsächlich einen größeren Leistungseinbruch bedeuten würden, als nur die Sprache zu überprüfen. Wenn Sie also bereits wissen, dass $ entity-> language existiert, können Sie einfach Ihre eigene super-performante Funktion schreiben:

function my_super_performant_field_value_getter($entity, $field_name) {
  return isset($entity->{$field_name}[{$entity->language}]) ? $entity->{$field_name}[{$entity->language}] : FALSE;
}
Charlie Schliesser
quelle
Ok, abgesehen von diesen Überprüfungen wird die Entität einmal geladen, egal wie oft ich sie verwende? Auch wenn ich Entitätsreferenzen verwende?
Florian Margaine
Ja, dies ist eine ziemlich coole Funktion der Entity-API in D7. Sobald Sie eine Entität geladen haben, wird sie für die Dauer dieser Anforderung zwischengespeichert. Wenn Sie dies $node = node_load(123);in einem Skript tun und an anderer Stelle erneut ausführen, entsteht kein Leistungsaufwand für das vollständige Laden und Erstellen von Objekten. Drupal weist dieser Variablen lediglich eine Kopie der vorhandenen Entität zu. Wenn Sie eine neue Kopie laden möchten , müssen Sie diese $reset = TRUEan die Entitätsladefunktion übergeben. Siehe auch meine Änderungen in Bezug auf einen super performanten Getter.
Charlie Schliesser
1
if (isset($node->field_my_field_name[LANGUAGE_NONE]) && isset($node->field_my_field_name[LANGUAGE_NONE][0])) {ist nicht notwendig, isset($node->field_my_field_name[LANGUAGE_NONE][0]ist genug.
@chx Ich stimme zu, aber wäre es nicht so isset($node->field_my_field_name[LANGUAGE_NONE]), da die Sprache nicht auf ein leeres Feld gesetzt wird? Ich denke, es ist das Delta [0], das überflüssig ist.
Charlie Schliesser
1
@GilesB, mehr Datenbankabfragen sind meistens nicht besser als Joins. Eifriges Laden ist eine Optimierungstechnik. Aber selbst wenn ich das sage, denke ich, dass Ihre Annahme falsch ist und EntityMetadataWrapper wahrscheinlich langsamer ist, aber es ist viel schöner zu verwenden. Dies ist auch eine Mikrooptimierung, über die OP bei der Arbeit mit Drupal nicht nachdenken muss.
Nicholas Ruunu