• Drupal 7.23:函数drupal_alter()注释


      1 /**
      2  * Passes alterable variables to specific hook_TYPE_alter() implementations.
      3  *
      4  * This dispatch function hands off the passed-in variables to type-specific
      5  * hook_TYPE_alter() implementations in modules. It ensures a consistent
      6  * interface for all altering operations.
      7  *
      8  * A maximum of 2 alterable arguments is supported (a third is supported for
      9  * legacy reasons, but should not be used in new code). In case more arguments
     10  * need to be passed and alterable, modules provide additional variables
     11  * assigned by reference in the last $context argument:
     12  * @code
     13  *   $context = array(
     14  *     'alterable' => &$alterable,
     15  *     'unalterable' => $unalterable,
     16  *     'foo' => 'bar',
     17  *   );
     18  *   drupal_alter('mymodule_data', $alterable1, $alterable2, $context);
     19  * @endcode
     20  *
     21  * Note that objects are always passed by reference in PHP5. If it is absolutely
     22  * required that no implementation alters a passed object in $context, then an
     23  * object needs to be cloned:
     24  * @code
     25  *   $context = array(
     26  *     'unalterable_object' => clone $object,
     27  *   );
     28  *   drupal_alter('mymodule_data', $data, $context);
     29  * @endcode
     30  *
     31  * @param $type
     32  *   A string describing the type of the alterable $data. 'form', 'links',
     33  *   'node_content', and so on are several examples. Alternatively can be an
     34  *   array, in which case hook_TYPE_alter() is invoked for each value in the
     35  *   array, ordered first by module, and then for each module, in the order of
     36  *   values in $type. For example, when Form API is using drupal_alter() to
     37  *   execute both hook_form_alter() and hook_form_FORM_ID_alter()
     38  *   implementations, it passes array('form', 'form_' . $form_id) for $type.
     39  * @param $data
     40  *   The variable that will be passed to hook_TYPE_alter() implementations to be
     41  *   altered. The type of this variable depends on the value of the $type
     42  *   argument. For example, when altering a 'form', $data will be a structured
     43  *   array. When altering a 'profile', $data will be an object.
     44  * @param $context1
     45  *   (optional) An additional variable that is passed by reference.
     46  * @param $context2
     47  *   (optional) An additional variable that is passed by reference. If more
     48  *   context needs to be provided to implementations, then this should be an
     49  *   associative array as described above.
     50  * @param $context3
     51  *   (optional) An additional variable that is passed by reference. This
     52  *   parameter is deprecated and will not exist in Drupal 8; consequently, it
     53  *   should not be used for new Drupal 7 code either. It is here only for
     54  *   backwards compatibility with older code that passed additional arguments
     55  *   to drupal_alter().
     56  */
     57 function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL, &$context3 = NULL) {
     58   // Use the advanced drupal_static() pattern, since this is called very often.
     59   static $drupal_static_fast;
     60   if (!isset($drupal_static_fast)) {
     61     $drupal_static_fast['functions'] = &drupal_static(__FUNCTION__);
     62   }
     63   $functions = &$drupal_static_fast['functions'];
     64 
     65   // Most of the time, $type is passed as a string, so for performance,
     66   // normalize it to that. When passed as an array, usually the first item in
     67   // the array is a generic type, and additional items in the array are more
     68   // specific variants of it, as in the case of array('form', 'form_FORM_ID').
     69   if (is_array($type)) {
     70     $cid = implode(',', $type);
     71     $extra_types = $type;
     72     $type = array_shift($extra_types);
     73     // Allow if statements in this function to use the faster isset() rather
     74     // than !empty() both when $type is passed as a string, or as an array with
     75     // one item.
     76     if (empty($extra_types)) {
     77       unset($extra_types);
     78     }
     79   }
     80   else {
     81     $cid = $type;
     82   }
     83 
     84   // Some alter hooks are invoked many times per page request, so statically
     85   // cache the list of functions to call, and on subsequent calls, iterate
     86   // through them quickly.
     87   if (!isset($functions[$cid])) {
     88     $functions[$cid] = array();
     89     $hook = $type . '_alter';
     90     $modules = module_implements($hook);
     91     if (!isset($extra_types)) {
     92       // For the more common case of a single hook, we do not need to call
     93       // function_exists(), since module_implements() returns only modules with
     94       // implementations.
     95       foreach ($modules as $module) {
     96         $functions[$cid][] = $module . '_' . $hook;
     97       }
     98     }
     99     else {
    100       // For multiple hooks, we need $modules to contain every module that
    101       // implements at least one of them.
    102       $extra_modules = array();
    103       foreach ($extra_types as $extra_type) {
    104         $extra_modules = array_merge($extra_modules, module_implements($extra_type . '_alter'));
    105       }
    106       // If any modules implement one of the extra hooks that do not implement
    107       // the primary hook, we need to add them to the $modules array in their
    108       // appropriate order. module_implements() can only return ordered
    109       // implementations of a single hook. To get the ordered implementations
    110       // of multiple hooks, we mimic the module_implements() logic of first
    111       // ordering by module_list(), and then calling
    112       // drupal_alter('module_implements').
    113       if (array_diff($extra_modules, $modules)) {
    114         // Merge the arrays and order by module_list().
    115         $modules = array_intersect(module_list(), array_merge($modules, $extra_modules));
    116         // Since module_implements() already took care of loading the necessary
    117         // include files, we can safely pass FALSE for the array values.
    118         $implementations = array_fill_keys($modules, FALSE);
    119         // Let modules adjust the order solely based on the primary hook. This
    120         // ensures the same module order regardless of whether this if block
    121         // runs. Calling drupal_alter() recursively in this way does not result
    122         // in an infinite loop, because this call is for a single $type, so we
    123         // won't end up in this code block again.
    124         drupal_alter('module_implements', $implementations, $hook);
    125         $modules = array_keys($implementations);
    126       }
    127       foreach ($modules as $module) {
    128         // Since $modules is a merged array, for any given module, we do not
    129         // know whether it has any particular implementation, so we need a
    130         // function_exists().
    131         $function = $module . '_' . $hook;
    132         if (function_exists($function)) {
    133           $functions[$cid][] = $function;
    134         }
    135         foreach ($extra_types as $extra_type) {
    136           $function = $module . '_' . $extra_type . '_alter';
    137           if (function_exists($function)) {
    138             $functions[$cid][] = $function;
    139           }
    140         }
    141       }
    142     }
    143     // Allow the theme to alter variables after the theme system has been
    144     // initialized.
    145     global $theme, $base_theme_info;
    146     if (isset($theme)) {
    147       $theme_keys = array();
    148       foreach ($base_theme_info as $base) {
    149         $theme_keys[] = $base->name;
    150       }
    151       $theme_keys[] = $theme;
    152       foreach ($theme_keys as $theme_key) {
    153         $function = $theme_key . '_' . $hook;
    154         if (function_exists($function)) {
    155           $functions[$cid][] = $function;
    156         }
    157         if (isset($extra_types)) {
    158           foreach ($extra_types as $extra_type) {
    159             $function = $theme_key . '_' . $extra_type . '_alter';
    160             if (function_exists($function)) {
    161               $functions[$cid][] = $function;
    162             }
    163           }
    164         }
    165       }
    166     }
    167   }
    168 
    169   foreach ($functions[$cid] as $function) {
    170     $function($data, $context1, $context2, $context3);
    171   }
    172 }

    drupal_alter()函数提供一个对钩子系统的调用,实现对系统变量的自定义修改。例如:当系统处于维护状态时,网站应该只允许管理员访问,一般访问者只能看到“系统处于维护状态”这样的提示信息。一般访问者访问网站时,若是在变更维护状态之前已经登录网站,这时user模块提供一个钩子,实现访问者的自动注销。

    // menu.inc的501-508行
    $site_status = variable_get('maintenance_mode') ? MENU_SITE_OFFLINE : MENU_SITE_ONLINE;
    drupal_alter('menu_site_status', $site_status , $_GET['q']);

    drupal_alter()会调用形如hook_TYPE_alter这样的钩子,此例子中是user模块的user_menu_site_status_alter()函数:

    // user.module的1834-1874行
    function user_menu_site_status_alter(&$menu_site_status, $path) {
      if ($menu_site_status == MENU_SITE_OFFLINE) {
        // If the site is offline, log out unprivileged users.
        if (user_is_logged_in() && !user_access('access site in maintenance mode')) {
          module_load_include('pages.inc', 'user', 'user');
          user_logout();
        }
    
        ... ...
      }
    
      ...
    }

    第57行:注意参数$data,是引用定义的,也可以理解为传址。再看一下user_menu_site_status_alter()钩子的参数,这里的$menu_site_status也是引用定义,和$data刚好对应。也就是说,在user_menu_site_status_alter()中修改$menu_site_status的值,也就是在修改$data的值。
    以此类推,drupal_alter()定义了三个context参数,也都是引用定义的。所以,在钩子函数中如果有需要,也可以修改这三个context参数的值:

    function hook_menu_site_status_alter(&$menu_site_status, &$context1, &$context2, &$context3) {
      $context1 = 'new value';
      ... ...
    }

    第143-144行:drupal_alter()被调用时,theme系统有可能准备就绪,也有可能尚未就绪。通过全局变量$theme可以判断theme系统是否就绪:

    global $theme;
    if (isset($theme)) {
      // theme系统准备就绪
    } else {
      // theme系统尚未就绪
    }

    除了module可以提供钩子(格式如:module_TYPE_alter)修改变量值以外,theme也可以提供钩子(格式:theme_TYPE_alter)修改变量值。所以,drupal必须要求模块和主题命名的唯一。

  • 相关阅读:
    工具
    选择排序
    c#中queue的用法
    c#加密
    话谈c#拷贝
    const与readonly的区别
    WinForm中使MessageBox实现可以自动关闭功能
    c#winform关闭窗口时触发的事件
    委托
    C# STA和MTA线程设置
  • 原文地址:https://www.cnblogs.com/eastson/p/3254446.html
Copyright © 2020-2023  润新知