ข้อใดมีประสิทธิภาพมากกว่านี้: 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()incurs ศูนย์ค่าใช้จ่ายในฐานข้อมูลดังนั้นฉันคิดว่านั่นเป็นกรณีที่สวยเปิดและปิด :)
ไคลฟ์

@Clive ทำไมจึงfield_get_items()เกิดศูนย์ค่าใช้จ่ายฐานข้อมูล? มันต้องได้รับข้อมูลที่ไหนสักแห่งใช่ไหม?
Florian Margaine

นอกจากนี้ฉันสนใจที่จะรู้วิธีการentity_metadata_wrapperทำงานประสิทธิภาพที่ชาญฉลาด
Florian Margaine

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'];แต่นั่นจะทำให้เกิดข้อผิดพลาดในการแจ้งเตือนของ 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())คุณจะเห็นว่ามันไม่ได้ทำอะไรมากไปกว่านั้นให้แน่ใจว่าอาร์เรย์ของฟิลด์มีข้อมูลเป็นภาษาที่อยู่ในแนว curent แล้วส่งกลับมา ดังนั้นค่าใช้จ่ายในการใช้งานฟังก์ชั่นเล็ก ๆ น้อย ๆ นั้นมีน้อยมาก แต่ถ้าคุณกังวลกับผลการปฏิบัติงานจริงๆคุณสามารถตรวจสอบด้วยตัวเองได้หากมีข้อมูลอยู่แล้วพิมพ์ออกมา

แก้ไข:เนื่องจากการfield_get_items()รันfield_language()จะมีผลการดำเนินงานที่ใหญ่กว่าการตรวจสอบภาษาดังนั้นหากคุณรู้อยู่แล้วว่ามีภาษา $ เอนทิตี้ -> อยู่คุณสามารถเขียนฟังก์ชัน super-performant ของคุณเอง:

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

ใช่นี่เป็นคุณสมบัติที่ยอดเยี่ยมของเอนทิตี API ใน D7 เมื่อคุณโหลดเอนทิตีมันจะถูกแคชในช่วงเวลาของคำขอนั้น ดังนั้นถ้าคุณทำ$node = node_load(123);ใน 1 สคริปต์และทำอย่างนั้นที่อื่นคุณไม่ต้องเสียค่าใช้จ่ายด้านประสิทธิภาพของการโหลดวัตถุและบิลด์แบบเต็ม Drupal เพียงแค่กำหนดตัวแปรให้กับสำเนาของเอนทิตีที่มีอยู่ หากคุณต้องการโหลดสำเนาใหม่คุณต้องผ่าน$reset = TRUEไปยังฟังก์ชันโหลดเอนทิตี นอกจากนี้ดูการแก้ไขของฉันเกี่ยวกับทะเยอทะยานนักแสดงสุด
Charlie Schliesser

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

1
@GilesB แบบสอบถามฐานข้อมูลเพิ่มเติมส่วนใหญ่มักจะไม่ดีกว่าการเข้าร่วม โหลดกระตือรือร้นเป็นเทคนิคการเพิ่มประสิทธิภาพ แต่ถึงแม้จะบอกว่าฉันคิดว่าการสันนิษฐานของคุณเป็นเท็จและ EntityMetadataWrapper อาจจะช้ากว่า แต่ก็ดีกว่าที่จะใช้ นี่คือการเพิ่มประสิทธิภาพขนาดเล็ก OP ไม่ต้องคิดเมื่อทำงานกับ Drupal
Nicholas Ruunu
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.