Как передать данные между хуками, которые не взаимодействуют?

10

Как передать данные между хуками, которые не взаимодействуют между ними, или между обратным вызовом меню и хуком?

В случае, если у двух хуков есть общий параметр, и этот параметр передается по ссылке, это легко. Что мне делать, если хуки или обратный вызов меню и хук не получают общего параметра?

Letharion
источник

Ответы:

12

В Drupal 7 или выше используйте статическую переменную, обработанную с помощью drupal_static () .
drupal_static()это функция, которая обрабатывает центральное хранилище для статических переменных. В отличие от переменных, объявленных с использованием staticключевого слова, статические переменные, с drupal_static()которыми обрабатываются , доступны из каждой функции; это возможно, потому что drupal_static()возвращает содержимое переменной по ссылке, позволяя каждой функции изменять его.

Предположим, что вам нужно передать значение между обработчиком меню и реализацией hook_block_view () ; Вы можете использовать следующий код.

function mymodule_menu() {
  return array('path/%' => array(
    'page callback' => 'mymodule_callback_function',
    'page arguments' => array(1),
  ));
}

function mymodule_callback_function($data) {
  $data_passer = &drupal_static('mymodule_block_data');

  $data_passer = $data;

  // Other logic specific to this page callback.
}

function mymodule_block_view($delta = '') {
  // $data_passer will now contain the value of $data, from above.
  $data_passer = &drupal_static('mymodule_block_data');

  // Change the block content basing on the content of $data_passer.
}

В случае, если к данным нужно обращаться чаще, вы должны использовать статическую локальную переменную, которая будет содержать значение, возвращаемое из drupal_static(). Поскольку статические переменные могут быть инициализированы только из буквального значения , а статические переменные не могут быть назначены ссылкам , единственный рабочий код аналогичен следующему. (Этот код взят из user_access () .)

  // Use the advanced drupal_static() pattern, since this is called very often.
  static $drupal_static_fast;
  if (!isset($drupal_static_fast)) {
    $drupal_static_fast['perm'] = &drupal_static(__FUNCTION__);
  }
  $perm = &$drupal_static_fast['perm'];

Возвращаемое значение drupal_static()сбрасывается каждый раз при загрузке Drupal; если вам нужно значение, которое сохраняется между различными страницами, то вам нужно использовать таблицу базы данных для хранения значения или использовать variable_get () / variable_set () .

Drupal 6 не реализует drupal_static(), но вы можете скопировать его код в функцию, определенную в вашем собственном модуле.

function &mymodule_static($name, $default_value = NULL, $reset = FALSE) {
  static $data = array(), $default = array();

  // First check if dealing with a previously defined static variable.
  if (isset($data[$name]) || array_key_exists($name, $data)) {
    // Non-NULL $name and both $data[$name] and $default[$name] statics exist.
    if ($reset) {
      // Reset pre-existing static variable to its default value.
      $data[$name] = $default[$name];
    }
    return $data[$name];
  }

  // Neither $data[$name] nor $default[$name] static variables exist.
  if (isset($name)) {
    if ($reset) {
      // Reset was called before a default is set and yet a variable must be
      // returned.
      return $data;
    }
    // First call with new non-NULL $name. Initialize a new static variable.
    $default[$name] = $data[$name] = $default_value;
    return $data[$name];
  }

  // Reset all: ($name == NULL). This needs to be done one at a time so that
  // references returned by earlier invocations of drupal_static() also get
  // reset.
  foreach ($default as $name => $value) {
    $data[$name] = $value;
  }

  // As the function returns a reference, the return should always be a
  // variable.
  return $data;
}

Перед использованием статической переменной с drupal_static()(или функцией обратного переноса, определенной в вашем модуле), вы должны помнить следующее:

  • Код работает только тогда, когда код, который устанавливает статическую переменную, выполняется перед кодом, чтобы получить его значение; если порядок выполнения не продуман, код не работает. Когда порядок выполнения не четко определен в документации Drupal, существует риск изменения порядка в будущих версиях Drupal; убедитесь, что порядок выполнения не меняется в версии Drupal, для которой вы реализуете свой код.
  • Drupal мог бы реализовать механизм для обмена данными между различными хуками. Например, в случае различных реализаций hook_form_alter () каждая реализация может обмениваться данными с другими hook_form_alter()реализациями, используя $form_state; таким же образом обработчики проверки формы и обработчики отправки формы могут совместно использовать данные, используя $form_stateпараметр, который передается по ссылке. Прежде чем реализовывать свой собственный код, убедитесь, что можно обмениваться данными, используя другой механизм, уже реализованный Drupal для конкретного случая.
kiamlaluno
источник
Очень ценю ответ, приведенный здесь для оригинального постера. Однако меня беспокоит то, что мне сказали, что использование статических переменных drupal не очень хорошо масштабируется - для сайтов, обрабатывающих большое количество запросов, из-за того, что весь набор переменных загружается каждый раз для каждой сессии (или что-то вроде это.) Мне сказал это коллега, который работал над проблемой производительности, связанной с этим. Что вы думаете? Они посоветовали, что использование кеша Drupal было бы лучшим способом передачи переменных (при условии, что они не нужны после получения данных кодом назначения)
therobyouknow
@therobyouknow "для сайтов, обрабатывающих много запросов, из-за того, что каждый раз загружается весь набор переменных", это таблица переменных , а не любая статическая переменная, что совершенно другое. сами статические переменные оказывают незначительное влияние на производительность. Даже в таблице переменных вам придется много злоупотреблять системой, чтобы вызвать проблемы. Economist.com может легко иметь несколько 100 тыс. Обращений в час, каждый из которых загружает таблицу переменных. Переменные не являются проблемой, но, конечно, мы храним только небольшие фрагменты информации в каждой переменной.
Летарион