entity_metadata_wrapperとfield_get_itemsのどちらがより優れていますか?


10

エンティティから値を取得するには、2つの方法があります。

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

しかし、私の質問はパフォーマンスについてより懸念しています。どちらもどのように機能しますか?彼らは値を要求するたびにデータベースをクエリしますか?DOESは、entity_metadata_wrapper一度にすべてを要求しますか?(field_get_item単一値検索により適しています。)

Drupalのソースを深く掘り下げるのに十分な勇気はありません。


1
field_view_field()フィールドをレンダリングするためのものです。フィールドの値を取得する関数はfield_get_items()です。
kiamlaluno

そして、field_get_items()私はそれが:)かなりオープンでシャットケースだと思うので招き、データベースのオーバーヘッドをゼロ
クライヴ

@Cliveでfield_get_items()データベースオーバーヘッドが発生しない理由 どこかでデータを取得する必要がありますよね?
Florian Margaine、2012年

また、私はentity_metadata_wrapperパフォーマンス面でどのように機能するかを知ることに本当に興味があります。
Florian Margaine、2012年

2
完全にロードされたエンティティオブジェクトをに渡すと、field_get_items()オーバーヘッドがすでに発生しています...正直に言うと、D7で絞め殺されたルートのビットです
Clive

回答:


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'];が、フィールドに値がない場合、存在しない可能性のある配列(つまり[LANGUAGE_NONE][0]['value'])にアクセスしようとしているため、PHP通知エラーがスローされます。私は最近これをかなり頻繁にやっていることに気づきます:

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->言語が存在することを知っていれば、そう、あなたは自分自身のスーパーパフォーマンス関数を書くことができます:

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

OK、それで、これらのチェックとは別に、エンティティを何回使用してもエンティティは1回読み込まれますか?エンティティ参照を使用しても
Florian Margaine、2012年

はい、これは実際にはD7のエンティティAPIのかなりクールな機能です。エンティティをロードすると、そのリクエストの間はキャッシュされます。したがって、$node = node_load(123);1つのスクリプトで実行し、それを他の場所で再度実行しても、完全なオブジェクトのロードとビルドのパフォーマンスオーバーヘッドが発生することはありません。Drupalは、その変数に既存のエンティティのコピーを割り当てるだけです。新しいコピーをロードする場合は$reset = TRUE、エンティティロード関数に渡す必要があります。また、高性能のゲッターに関する私の編集を参照してください。
チャーリーシュリーサー、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]冗長なのはdelta /だと思います。
チャーリーシュリーサー2013

1
@GilesB、多くの場合、データベースクエリは結合よりも優れているとは言えません。熱心な読み込みは最適化手法です。しかし、それを言っても、私はあなたの仮定は偽であり、EntityMetadataWrapperはおそらく遅いと思いますが、それを使うのはとても良いです。これはまた、マイクロ最適化OPであり、Drupalを使用するときに考慮する必要はありません。
Nicholas Ruunu 2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.