¿Cuál es más eficaz: entity_metadata_wrapper o field_get_items?

10

Para obtener valores de entidades, hay dos formas:

  • Use field_get_itemsy obtenga el valor de un campo
  • Use entity_metadata_wrappery obtenga el valor de un campo

Aunque entity_metadata_wrapperabstrae las diferencias de idioma, su API todavía es incómoda a veces, especialmente cuando se usa PHP 5.3. Por ejemplo, obtener el valor de un campo de texto largo generalmente sigue esta ruta:

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

Afortunadamente, PHP 5.4 es compatible con esta sintaxis: print $wrapper->field->value()['safe_value'];.

Pero mi pregunta está más preocupada por el rendimiento. ¿Cómo funcionan ambos? ¿Consultan la base de datos cada vez que solicitan un valor? ¿ entity_metadata_wrapperSolicita todo a la vez? (Hacer field_get_itemmás adecuado para recuperaciones de un solo valor).

No soy lo suficientemente valiente como para sumergirme profundamente en la fuente de Drupal.

Florian Margaine
fuente
1
field_view_field()es para representar un campo. La función para obtener el valor de un campo es field_get_items () .
kiamlaluno
E field_get_items()incurre en cero sobrecarga de la base de datos, así que creo que es un caso bastante abierto y cerrado :)
Clive
@Clive ¿cómo es que field_get_items()incurre en gastos generales de base de datos cero? Tiene que obtener sus datos en alguna parte, ¿verdad?
Florian Margaine
Además, estoy realmente interesado en saber cómo entity_metadata_wrapperfunciona, en cuanto al rendimiento.
Florian Margaine
2
Se pasa un objeto de entidad completamente cargado field_get_items()para que la sobrecarga ya se haya incurrido ... es un poco una ruta estrangulada en D7 para ser honesto
Clive

Respuestas:

12

La respuesta corta: field_get_items () es más eficiente que entity_metadata_wrapper ().

Consulte el código para estas funciones:

Ambos requieren que pase la entidad, que ya se ha cargado desde la base de datos . Por ejemplo:

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

o, como ya has sugerido:

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

Ambas instancias me molestan debido a la lógica tonta al tratar de obtener un valor que ya está disponible para usted, pero ciertamente son útiles en muchos casos.

Simplemente podría hacerlo, print $node->field_my_field_name[LANGUAGE_NONE][0]['value'];pero eso arrojaría errores de aviso de PHP si el campo no tiene un valor, ya que está intentando acceder a matrices que pueden no existir (es decir [LANGUAGE_NONE][0]['value']). Últimamente me encuentro haciendo esto muy a menudo:

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

que es mucho más limpio que hacerlo:

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

Si observa el código field_get_items()), verá que no está haciendo nada más que asegurarse de que la matriz del campo tenga datos en el lenguaje actual y luego los devuelva. Por lo tanto, la sobrecarga de ejecutar una función tan pequeña es insignificante, pero si realmente le preocupa el rendimiento, puede hacer su propia verificación si los datos existen y luego imprimirlos.

Editar: dado que las field_get_items()ejecuciones en field_language()realidad habría un mayor impacto en el rendimiento que simplemente verificar el idioma, por lo tanto, si ya sabe que $ entity-> language existe, podría escribir su propia función super-performance:

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
fuente
Ok, aparte de esas comprobaciones, la entidad se carga una vez, sin importar cuántas veces las use. ¿Incluso si uso referencias de entidad?
Florian Margaine
Sí, esta es realmente una característica genial de la API de la entidad en D7. Una vez que carga una entidad, se almacena en caché durante la duración de esa solicitud. Por lo tanto, si lo hace $node = node_load(123);en 1 script y lo hace de nuevo en otro lugar, no incurrirá en la sobrecarga de rendimiento de una carga y construcción de objetos completos: Drupal solo asigna a esa variable una copia de la entidad existente. Si desea cargar una nueva copia, debe pasar $reset = TRUEa la función de carga de la entidad. Además, vea mis ediciones con respecto a un getter súper performante.
Charlie Schliesser
1
if (isset($node->field_my_field_name[LANGUAGE_NONE]) && isset($node->field_my_field_name[LANGUAGE_NONE][0])) {No es necesario, isset($node->field_my_field_name[LANGUAGE_NONE][0]es suficiente.
@chx Estoy de acuerdo, pero ¿no sería así isset($node->field_my_field_name[LANGUAGE_NONE]), ya que el idioma no se establecerá en un campo vacío? Creo que es el delta / [0]que es redundante.
Charlie Schliesser
1
@GilesB, más consultas de bases de datos a menudo no son mejores que las uniones. La carga ansiosa es una técnica de optimización. Pero incluso diciendo eso, creo que su suposición es falsa y EntityMetadataWrapper es probablemente más lento, pero es mucho más agradable de usar. Esta es también una optimización de micro OP que no tiene que pensar al trabajar con Drupal.
Nicholas Ruunu