Cái nào hiệu quả hơn: entity_metadata_wrapper hoặc field_get_items?


10

Để nhận giá trị từ các thực thể, có hai cách:

  • Sử dụng field_get_itemsvà nhận giá trị của một trường
  • Sử dụng entity_metadata_wrappervà nhận giá trị của một trường

Mặc dù entity_metadata_wrappertrừu tượng hóa sự khác biệt ngôn ngữ, đôi khi API của nó vẫn còn lúng túng, đặc biệt là khi sử dụng PHP 5.3. Ví dụ: nhận giá trị của trường văn bản dài thường đi theo tuyến đường này:

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

May mắn thay, PHP 5.4 hỗ trợ cú pháp này : print $wrapper->field->value()['safe_value'];.

Nhưng câu hỏi của tôi quan tâm nhiều hơn về hiệu suất. Làm thế nào để cả hai làm việc? Họ có truy vấn cơ sở dữ liệu mỗi khi họ yêu cầu một giá trị không? Có entity_metadata_wrapperyêu cầu tất cả mọi thứ cùng một lúc? (Làm cho field_get_itemphù hợp hơn với truy xuất giá trị đơn.)

Tôi không đủ can đảm để đi sâu vào nguồn Drupal.


1
field_view_field()là để hiển thị một trường. Hàm để lấy giá trị của một trường là field_get_items () .
kiamlaluno

field_get_items()không phát sinh chi phí cơ sở dữ liệu nên tôi nghĩ đó là một trường hợp khá mở và đóng :)
Clive

@Clive làm thế nào để field_get_items()phát sinh cơ sở dữ liệu không? Nó phải lấy dữ liệu của nó ở đâu đó, phải không?
Florian Margaine

Ngoài ra, tôi thực sự quan tâm đến việc làm thế nào entity_metadata_wrapperhoạt động, hiệu suất khôn ngoan.
Florian Margaine

2
Bạn chuyển một đối tượng thực thể được tải đầy đủ vào field_get_items()để chi phí phát sinh đã bị phát sinh ... đó là một chút tuyến đường bị bóp nghẹt trong D7 phải trung thực
Clive

Câu trả lời:


12

Câu trả lời ngắn: field_get_items () có hiệu suất cao hơn so với entity_metadata_wrapper ().

Kiểm tra mã cho các chức năng này:

Cả hai đều yêu cầu bạn chuyển dọc theo thực thể, đã được tải từ cơ sở dữ liệu . Ví dụ:

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

hoặc, như bạn đã đề xuất:

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

Cả hai trường hợp này đều làm phiền tôi vì logic ngớ ngẩn khi cố gắng có được một giá trị đã có sẵn cho bạn, nhưng chúng chắc chắn hữu ích trong nhiều trường hợp.

Bạn chỉ có thể làm print $node->field_my_field_name[LANGUAGE_NONE][0]['value'];nhưng điều đó sẽ gây ra lỗi thông báo PHP nếu trường không có giá trị, vì bạn đang cố truy cập các mảng có thể không tồn tại (ví dụ [LANGUAGE_NONE][0]['value']). Tôi thấy mình làm điều này khá thường xuyên gần đây:

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

đó là sạch hơn rất nhiều so với làm:

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

Nếu bạn nhìn vào mã cho field_get_items())bạn sẽ thấy rằng nó không làm gì thêm thì hãy đảm bảo rằng mảng của trường có dữ liệu bằng ngôn ngữ hiện tại và sau đó trả về nó. Vì vậy, chi phí hoạt động của một chức năng nhỏ như vậy là không đáng kể, nhưng nếu bạn thực sự quan tâm đến hiệu suất, bạn có thể tự kiểm tra nếu dữ liệu tồn tại và sau đó in nó.

Chỉnh sửa: Vì các field_get_items()lần chạy field_language()thực sự sẽ có hiệu suất lớn hơn so với việc chỉ kiểm tra ngôn ngữ, vì vậy, nếu bạn đã biết rằng ngôn ngữ $ entity-> tồn tại, bạn có thể viết hàm siêu hiệu suất của riêng mình:

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

Ok, vậy ngoài những kiểm tra đó, thực thể được tải một lần, bất kể tôi sử dụng chúng bao nhiêu lần? Ngay cả khi tôi sử dụng tài liệu tham khảo thực thể?
Florian Margaine

Vâng, đây thực sự là một tính năng khá thú vị của API thực thể trong D7. Khi bạn tải một thực thể, nó được lưu trữ trong thời gian của yêu cầu đó. Vì vậy, nếu bạn thực hiện $node = node_load(123);trong 1 tập lệnh và thực hiện lại ở nơi khác, bạn sẽ không phải chịu chi phí hiệu năng của toàn bộ tải và xây dựng đối tượng - Drupal chỉ gán cho biến đó một bản sao của thực thể hiện có. Nếu bạn muốn tải một bản sao mới , bạn cần chuyển $reset = TRUEđến hàm tải thực thể. Ngoài ra, hãy xem các chỉnh sửa của tôi liên quan đến một getter siêu hiệu suất.
Charlie Schliesser

1
if (isset($node->field_my_field_name[LANGUAGE_NONE]) && isset($node->field_my_field_name[LANGUAGE_NONE][0])) {là không cần thiết, isset($node->field_my_field_name[LANGUAGE_NONE][0]là đủ.

@chx Tôi đồng ý, nhưng sẽ không như vậy isset($node->field_my_field_name[LANGUAGE_NONE]), vì ngôn ngữ sẽ không được đặt trên một trường trống? Tôi nghĩ đó là đồng bằng / [0]đó là dư thừa.
Charlie Schliesser

1
@GilesB, nhiều truy vấn cơ sở dữ liệu thường không tốt hơn tham gia. Tải háo hức là một kỹ thuật tối ưu hóa. Nhưng ngay cả khi nói điều đó, tôi nghĩ rằng giả định của bạn là sai và EntityMetadataWrapper có thể chậm hơn, nhưng nó sẽ dễ sử dụng hơn nhiều. Đây cũng là tối ưu hóa vi mô mà OP không phải suy nghĩ khi làm việc với Drupal.
Nicholas Ruunu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.