Quantcast
Channel: Issues for Drupal core
Viewing all articles
Browse latest Browse all 292355

Avoid costly lookups of drupal_array_get_nested_value / drupal_array_nested_key_exists

$
0
0

Problem/Motivation

drupal_array_nested_key_exists / drupal_array_get_nested_value is very costly and essentially always traverses the same path within either form_state['input'] / form_state['values'] .

field_x/und/0/_weight

etc.

The traversing itself can with 30 files go into direction of 300 - 500 ms alone already.

Proposed resolution

However form_builder() already traverses this path - unless someone overwrote it with arbitrary #parents - so in 90% of the cases, a reference could be put in $form_state or a new variable on where the form builder according to #tree and #parents should be right now in relation to the base of 'values' / 'input'.

e.g. pseudo code for values:

<?php
function form_builder() {
  // check if set first obviously.
  $current_values_element = &$form_state['form_builder_current']['values'];

  foreach (element_children(...) as $key) {
    // use $key only with #tree obviously.
    if (!isset($element[$key]['#parents'])) {
      if ($is_tree) {
        $form_state['form_builder_current']['values'] = &$current_values_element[$key];
      }
      else {
        $form_state['form_builder_current']['values'] = &$form_state['values'];
      }
    }
    else {
      $form_state['form_builder_current'] = array();
    }
      // ...
      form_builder(..., $form_state);
  }
}
?>

It is also possible to create short-cut cache paths based on the parents as string, but that is more effort than trailing along directly:

<?php
function &drupal_array_get_nested_value_cached(array &$array, array $parents, &$key_exists = NULL) {
  $ref = &$array;
  $i = 0;
  $path = '';
  $found = array();
  $paths = array();
  $skip = FALSE;

  foreach ($parents as $index => $parent) {
    $path .= '/' . $parent;
    if (isset($array['#form_builder_cached_path'][$path])) {
      $skip = $index;
      $ref = &$array['#form_builder_cached_path'][$path];
    }
  }

  $path = '';
  foreach ($parents as $index => $parent) {
    $path .= '/' . $parent;
    if ($skip !== FALSE) {
      if ($skip != $index) {
        continue;
      }
      $skip = FALSE;
      continue;
    }
    elseif (is_array($ref) && (isset($parent[$ref]) || array_key_exists($parent, $ref))) {
      $array['#form_builder_cached_path'][$path] = &$ref[$parent];
      $ref = &$ref[$parent];
    }
    else {
      $key_exists = FALSE;
      $null = NULL;
      return $null;
    }
  }
  $key_exists = TRUE;
  return $ref;
}

function drupal_array_nested_key_exists_cached(array &$array, array $parents) {
  // although this function is similar to php's array_key_exists(), its
  // arguments should be consistent with drupal_array_get_nested_value().
  $key_exists = null;
  drupal_array_get_nested_value_cached($array, $parents, $key_exists);
  return $key_exists;
}
?>

Remaining tasks

- See if one of the proposed approaches passes core tests.


Viewing all articles
Browse latest Browse all 292355

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>