Który jest bardziej wydajny: podmiot_metadane_wrapper lub field_get_items?

10

Aby uzyskać wartości z encji, istnieją dwa sposoby:

  • Użyj field_get_itemsi uzyskaj wartość pola
  • Użyj entity_metadata_wrapperi uzyskaj wartość pola

Chociaż entity_metadata_wrapperabstrahuje różnice językowe, jego interfejs API jest czasem niezręczny, szczególnie przy korzystaniu z PHP 5.3. Na przykład uzyskanie wartości długiego pola tekstowego zwykle przebiega tą drogą:

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

Na szczęście, PHP 5.4 obsługuje tej składni: print $wrapper->field->value()['safe_value'];.

Ale moje pytanie dotyczy bardziej wydajności. Jak one działają? Czy przeszukują bazę danych za każdym razem, gdy żądają wartości? Czy entity_metadata_wrapperżąda wszystkiego na raz? ( field_get_itemBardziej odpowiednie dla pobierania pojedynczej wartości.)

Nie mam dość odwagi, by zanurzyć się głęboko w źródle Drupala.

Florian Margaine
źródło
1
field_view_field()służy do renderowania pola. Funkcja uzyskiwania wartości pola to field_get_items () .
kiamlaluno
I field_get_items()powoduje zerowe obciążenie bazy danych, więc myślę, że to dość otwarta i zamknięta sprawa :)
Clive
@Clive, dlaczego przychodzi field_get_items()zerowy narzut bazy danych? Musi gdzieś dostać swoje dane, prawda?
Florian Margaine,
Jestem też bardzo zainteresowany wiedzą, jak entity_metadata_wrapperdziała, pod względem wydajności.
Florian Margaine,
2
Przekazujesz w pełni załadowany obiekt bytu, field_get_items()więc narzut już został poniesiony ... to jest trochę uduszona trasa w D7, szczerze mówiąc
Clive

Odpowiedzi:

12

Krótka odpowiedź: field_get_items () jest bardziej wydajna niż entity_metadata_wrapper ().

Sprawdź kod tych funkcji:

Oba wymagają przekazania elementu, który został już załadowany z bazy danych . Na przykład:

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

lub, jak już zasugerowałeś:

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

Oba te przypadki trochę mnie niepokoją z powodu głupiej logiki w próbie uzyskania wartości, która jest już dostępna, ale z pewnością są przydatne w wielu przypadkach.

Możesz po prostu zrobić, print $node->field_my_field_name[LANGUAGE_NONE][0]['value'];ale spowoduje to zgłoszenie błędów powiadomienia PHP, jeśli pole nie ma wartości, ponieważ próbujesz uzyskać dostęp do tablic, które mogą nie istnieć (tj [LANGUAGE_NONE][0]['value'].). Ostatnio często to robię:

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

co jest o wiele czystsze niż robienie:

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

Jeśli spojrzysz na kod field_get_items()), zobaczysz, że nie robi nic więcej niż upewnienie się, że tablica pola zawiera dane w bieżącym języku, a następnie zwraca go. Narzut związany z uruchomieniem tak małej funkcji jest znikomy, ale jeśli naprawdę zależy Ci na wydajności, możesz po prostu sprawdzić, czy dane istnieją, a następnie je wydrukować.

Edycja: Ponieważ field_get_items()biegi field_language()byłyby w rzeczywistości większym spadkiem wydajności niż tylko sprawdzanie języka, więc jeśli już wiesz, że istnieje $ byt-> język, możesz po prostu napisać własną funkcję nadrzędną:

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
źródło
Ok, więc oprócz tych kontroli jednostka jest ładowana raz, bez względu na to, ile razy ich używam? Nawet jeśli użyję referencji encji?
Florian Margaine,
Tak, w rzeczywistości jest to całkiem fajna funkcja interfejsu API encji w D7. Po załadowaniu obiektu jest on buforowany przez czas trwania tego żądania. Tak więc, jeśli zrobisz to $node = node_load(123);w 1 skrypcie i zrobisz to jeszcze raz w innym miejscu, nie ponosisz narzutu wydajności pełnego obciążenia obiektu i kompilacji - Drupal po prostu przypisuje tej zmiennej kopię istniejącej jednostki. Jeśli chcesz załadować nową kopię, musisz przejść $reset = TRUEdo funkcji ładowania encji. Zobacz także moje zmiany dotyczące super wydajnego narzędzia pobierającego.
Charlie Schliesser
1
if (isset($node->field_my_field_name[LANGUAGE_NONE]) && isset($node->field_my_field_name[LANGUAGE_NONE][0])) {nie jest konieczne, isset($node->field_my_field_name[LANGUAGE_NONE][0]wystarczy.
@chx Zgadzam się, ale czy nie byłoby tak isset($node->field_my_field_name[LANGUAGE_NONE]), ponieważ język nie będzie ustawiony na pustym polu? Myślę, że to delta / [0]jest zbędne.
Charlie Schliesser,
1
@GilesB, więcej zapytań do bazy danych najczęściej nie jest lepszych niż złączenia. Chętne ładowanie to technika optymalizacji. Ale nawet mówiąc to, myślę, że twoje założenie jest fałszywe, a EntityMetadataWrapper jest prawdopodobnie wolniejszy, ale jest o wiele ładniejszy w użyciu. Jest to również mikrooptymalizacja OP, o której nie trzeba myśleć podczas pracy z Drupalem.
Nicholas Ruunu,