zoukankan      html  css  js  c++  java
  • Drupal的钩子系统

    Drupal的很多功能都是可以定制的。以导航菜单为例,blog模块需要在菜单上添加一些功能,comment模块需要在菜单上添加一些功能,我们开发的自定义模块也需要在菜单上添加一些功能。Drupal开发者为了达到这样的扩展目的,设计了钩子系统,导航菜单就是其中一个名为menu的钩子。有了钩子系统,开发人员就可以在blog模块定义一个钩子函数从而实现menu钩子。Drupal要求钩子函数的命名必须要求以模块名开始,以钩子名为后缀。

    function block_menu() {
      $items['admin/structure/block/manage/%/%'] = array(
        'title' => 'Configure block',
        'page callback' => 'drupal_get_form',
        'page arguments' => array('block_admin_configure', 4, 5),
        'access arguments' => array('administer blocks'),
        'file' => 'block.admin.inc',
      );
      $items['admin/structure/block/manage/%/%/configure'] = array(
        'title' => 'Configure block',
        'type' => MENU_DEFAULT_LOCAL_TASK,
        'context' => MENU_CONTEXT_INLINE,
      );
      $items['admin/structure/block/manage/%/%/delete'] = array(
        'title' => 'Delete block',
        'page callback' => 'drupal_get_form',
        'page arguments' => array('block_custom_block_delete', 4, 5),
        'access arguments' => array('administer blocks'),
        'type' => MENU_LOCAL_TASK,
        'context' => MENU_CONTEXT_NONE,
        'file' => 'block.admin.inc',
      );
      
      ... ...
      
      return $items;
    }

    module_hook_info()函数查询所有可以实现的钩子,实质上也是使用的钩子方式:

    function module_hook_info() {
      $hook_info = array();
    
      foreach (module_list() as $module) {
        $function = $module . '_hook_info'; // hook_info钩子
        if (function_exists($function)) {
          $result = $function();
          if (isset($result) && is_array($result)) {
            $hook_info = array_merge_recursive($hook_info, $result);
          }
        }
      }
      
      // We can't use drupal_alter() for the same reason as above.
      foreach (module_list() as $module) {
        $function = $module . '_hook_info_alter'; // hook_info_alter钩子
        if (function_exists($function)) {
          $function($hook_info);
        }
      }
    
      return $hook_info;
    }

    自定义的钩子可以在hook_info中注册,也可以不注册。注册的好处是可以为钩子实现人员提供更详细的详细,另外一个目的是可以为钩子分组。例如,定义了很多admin有关的钩子,这些钩子函数我们想把它们单独放在一个PHP文件里面,而不用都挤在模块主文件。

    module_implements()函数返回实现某个钩子的所有函数,它用module_list()遍历当前激活的所哟模块:

    function module_implements($hook, $sort = FALSE, $reset = FALSE) {
      $implementations = &$drupal_static_fast['implementations'];
    
      if (!isset($implementations[$hook])) {
      
        $hook_info = module_hook_info(); // 查询钩子信息
        
        $implementations[$hook] = array();
        $list = module_list(FALSE, FALSE, $sort);
        foreach ($list as $module) {
        
          // 注意这里额外载入了钩子分组文件
          $include_file = isset($hook_info[$hook]['group']) && module_load_include('inc', $module, $module . '.' . $hook_info[$hook]['group']);
          
          // Since module_hook() may needlessly try to load the include file again,
          // function_exists() is used directly here.
          if (function_exists($module . '_' . $hook)) {
            $implementations[$hook][$module] = $include_file ? $hook_info[$hook]['group'] : FALSE;
          }
        }
        
        // Allow modules to change the weight of specific implementations but avoid
        // an infinite loop.
        if ($hook != 'module_implements_alter') {
          drupal_alter('module_implements', $implementations[$hook], $hook);
        }
      }
      else {
        foreach ($implementations[$hook] as $module => $group) {
          // If this hook implementation is stored in a lazy-loaded file, so include
          // that file first.
          if ($group) {
            // 注意这里额外载入了钩子分组文件
            module_load_include('inc', $module, "$module.$group");
          }
          
          // It is possible that a module removed a hook implementation without the
          // implementations cache being rebuilt yet, so we check whether the
          // function exists on each request to avoid undefined function errors.
          // Since module_hook() may needlessly try to load the include file again,
          // function_exists() is used directly here.
          if (!function_exists($module . '_' . $hook)) {
            // Clear out the stale implementation from the cache and force a cache
            // refresh to forget about no longer existing hook implementations.
            unset($implementations[$hook][$module]);
            $implementations['#write_cache'] = TRUE;
          }
        }
      }
    
      return array_keys($implementations[$hook]);
    }

    module_invoke_all()则调用所有实现某个钩子的所有函数,这是Drupal钩子系统的最外层接口:

    function module_invoke_all($hook) {
      $args = func_get_args();
      // Remove $hook from the arguments.
      unset($args[0]);
      $return = array();
      foreach (module_implements($hook) as $module) {
        $function = $module . '_' . $hook;
        if (function_exists($function)) {
          $result = call_user_func_array($function, $args); // 调用钩子函数
          if (isset($result) && is_array($result)) {
            $return = array_merge_recursive($return, $result); // 返回结果的处理方式
          }
          elseif (isset($result)) {
            $return[] = $result; // 返回结果的处理方式
          }
        }
      }
    
      return $return;
    }

    例如,我们要调用menu钩子,简单的调用module_invoke_all()就可以了:

    $items = module_invoke_all('menu');
  • 相关阅读:
    分布式服务框架 Zookeeper — 管理分布式环境中的数据
    分布式消息队列(二)
    分布式消息队列(一)
    数据库事务的四大特性以及事务的隔离级别
    php--yii2.0的安装
    php--字符串函数分类总结
    一张表有三个字段:id(城市id) Cityname(城市名) Privence(所属省份)如果要统计每个省份有多少城市请用SQL实现。
    TP自带的缓存机制
    php——n维数组的遍历——递归
    php--分享插件
  • 原文地址:https://www.cnblogs.com/eastson/p/3374366.html
Copyright © 2011-2022 走看看