哪个性能更高:entity_metadata_wrapper或field_get_items?


10

要从实体获取值,有两种方法:

  • 使用field_get_items并获取字段的值
  • 使用entity_metadata_wrapper并获取字段的值

尽管entity_metadata_wrapper抽象化了语言差异,但有时它的API仍然很笨拙,尤其是在使用PHP 5.3时。例如,获取长文本字段的值通常采用以下路线:

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

幸运的是,PHP 5.4支持以下语法:print $wrapper->field->value()['safe_value'];

但是我的问题是更关注性能。它们都如何工作?他们是否在每次请求值时查询数据库?是否entity_metadata_wrapper一次请求所有内容?(field_get_item更适合于单值检索。)

我不够勇敢地深入探究Drupal源。


1
field_view_field()用于渲染字段。获取字段值的函数是field_get_items()
kiamlaluno

并且field_get_items()导致零数据库开销,所以我认为这是一个很容易被关闭的情况:)
Clive

@Clive如何field_get_items()导致零数据库开销?它必须在某个地方获取数据,对吗?
Florian Margaine 2012年

另外,我真的很想知道entity_metadata_wrapper性能如何运作。
Florian Margaine 2012年

2
您将一个完全加载的实体对象传递到其中,field_get_items()因此已经产生了开销……说实话,这在D7中有点儿被绞死了
克莱夫(Clive)

Answers:


12

简短的答案:field_get_items()比entity_metadata_wrapper()更具性能。

查看这些功能的代码:

两者都要求您传递已经从数据库加载的实体。例如:

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

或者,正如您已经建议的:

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

由于试图获得已经可用的价值的愚蠢逻辑,这两种情况都令我感到困扰,但是它们在很多情况下肯定有用。

您可以这样做,print $node->field_my_field_name[LANGUAGE_NONE][0]['value'];但是如果该字段没有值,则会抛出PHP通知错误,因为您正尝试访问可能不存在的数组(即[LANGUAGE_NONE][0]['value'])。我发现自己最近经常这样做:

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

这比做起来要干净得多:

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

如果查看代码,field_get_items())您将发现它什么也没做,那么请确保该字段的数组包含当前语言的数据,然后将其返回。因此,运行这样一个小函数的开销可以忽略不计,但是如果您真的对性能有问题,则可以自己检查数据是否存在,然后打印出来。

编辑:由于field_get_items()运行field_language()实际上会比仅检查语言带来更大的性能影响,因此,如果您已经知道$ entity-> language存在,则可以编写自己的超级性能函数:

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

好的,因此除了这些检查之外,无论我使用多少次,实体都会加载一次。即使我使用实体引用?
Florian Margaine 2012年

是的,这实际上是D7中的实体API的一个很酷的功能。加载实体后,将在该请求期间将其缓存。因此,如果您$node = node_load(123);使用1个脚本执行此操作,然后再在其他位置执行此操作,则不会招致完整对象加载和构建的性能开销– Drupal只会为该变量分配现有实体的副本。如果要加载副本,则需要传递$reset = TRUE给实体加载功能。另外,请参阅我有关超级性能吸气剂的编辑内容。
Charlie Schliesser 2012年

1
if (isset($node->field_my_field_name[LANGUAGE_NONE]) && isset($node->field_my_field_name[LANGUAGE_NONE][0])) {没有必要,isset($node->field_my_field_name[LANGUAGE_NONE][0]就足够了。

@chx我同意,但是不是isset($node->field_my_field_name[LANGUAGE_NONE]),因为不会在空字段中设置语言?我认为这[0]是多余的增量/ 。
Charlie Schliesser 2013年

1
@GilesB,更多的数据库查询通常并不比联接更好。渴望加载是一种优化技术。但是,即使这么说,我认为您的假设是错误的,并且EntityMetadataWrapper可能会更慢,但是使用起来要好得多。这也是微优化OP在使用Drupal时不必考虑。
Nicholas Ruunu
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.