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');

Drupal的钩子系统的更多相关文章

  1. Docker——基于Docker安装Drupal博客系统

    Docker--基于Docker安装Drupal博客系统 向脚本文件追加内容 cat << EOF > build.sh #设置主机名 hostnamectl set-hostnam ...

  2. Drupal 7.23:函数drupal_alter()注释

    /** * Passes alterable variables to specific hook_TYPE_alter() implementations. * * This dispatch fu ...

  3. drupal node机制理解

    [1]根据结构的功能结构的不同,drupal划分为,node,user,comment等不同的结构,他们的结构是不同的.他们可以作为四个不同的抽象类,根据这个抽象类,分别有一套hook函数去控制实现的 ...

  4. Drupal theme_hook

    模板语言和主题引擎 用Drupal的行话来说,主题就是一组负责你站点外观的文件.你可以从http://drupal.org/project/Themes下载第 3方主题,或者你可以自己动手创建一个主题 ...

  5. PHP钩子机制

    什么是钩子 大家想必听过插件,wordpress插件特别多,这个就是用钩子机制实现的. 当代码在运行的过程中,我们预先在运行的几个特殊点里执行一些特殊方法:例如在运行方法(例如Blog::add的ad ...

  6. 高校应该使用 Drupal 的10大理由

    使用 Drupal 已经成为全球顶尖高校中的一种潮流,它已经被全球数以百计的院校选择并应用,无论是哈佛.斯坦福.杜克.布朗.罗格斯.剑桥.耶鲁还是其它众多知名高校,都已经选择 Drupal 作为它们理 ...

  7. PHP之运用CI用钩子实现URL权限控制————————【Badboy】

    <span style="background-color: rgb(247, 252, 255); font-family: Verdana, Arial, Helvetica, s ...

  8. 谈PHP中的钩子

    钩子,英文为hooks.在程序中应用相当广泛,但是究竟什么是钩子呢?本人介绍一下目前本人对钩子的理解和相关心得. 假如有这么一段程序流: function fun(){ funA(); funB(); ...

  9. [Drupal]主题教程

    drupal6和drupal7的主题开发有很大不同,本指南包含了这些不同 drupal7的默认主题是Bartik,6的是Garland drupal的主题系统是如何工作的 这部分内容主要讲述的是dru ...

随机推荐

  1. Codeforces 741B Arpa's weak amphitheater and Mehrdad's valuable Hoses

    [题目链接] http://codeforces.com/problemset/problem/741/B [题目大意] 给出一张图,所有连通块构成分组,每个点有价值和代价, 要么选择整个连通块,要么 ...

  2. [DesignPattern]Builder设计模式

    模式的定义 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 模式的使用场景 相同的方法,不同的执行顺序,产生不同的事件结果时: 多个部件或零件,都可以装配到一个对象中,但是 ...

  3. 一步一步搭建springCloud

    一.spring cloud简介Spring Cloud是一系列框架的有序集合.它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册.配置中心.消息总线.负载均 ...

  4. Mobiscroll手机触屏日期选择器

       最近在制作jquery mobile因要用到日历控件,突然发现Mobiscroll非常不错.于是摘下来记录. A Mobiscroll是一个用于触摸设备(Android phones.iPhon ...

  5. django邮件相关设置

    EMAIL_HOST = 'smtp.mxhichina.com' # 阿里云企业邮箱 EMAIL_HOST_PORT = 25 # 邮箱服务器端口 EMAIL_HOST_USER = '****** ...

  6. [转]Java五个最常用的集合类之间的区别和联系

    Map<String, ?>只能是只读模式,不能增加,因为增加的时候不知道该写入什么类型的值:Map<String, Object>可以读和写,只要是所有Object类的子类都 ...

  7. LNMP一键包屏蔽PHP报错信息开启方法

    在 php-fpm.conf中的[www]下添加php_flag[display_errors] = On 重启php-fpm即可 /etc/init.d/php-fpm restart

  8. 微信小程序,工具未检测合法域名,400 (Bad Request)错误

    1.工具未检测合法域名 这个我就不多说了,如果你新建的时候没有填写AppID的话这个我就不太清楚了 如果新建项目的时候填写了AppID的话,出现这种错误,那你应该去小程序后台 设置->开发者设置 ...

  9. 【很变态】PHP类实例化对象竟然可以访问类的“静态(static)方法”!!!

    之前发现一个PHP的变态问题:PHP中静态(static)调用非静态方法详解 这次看了下 ThinkPHP 的源码 function.inc.php ,里面有个函数: /** * 取得对象实例 支持调 ...

  10. Linux操作系统下的常见系统资源共享

    转:http://www.360doc.com/content/07/0420/10/25127_457022.shtml linux下如何挂接(mount)光盘镜像文件.移动硬盘.U盘.Window ...