作者:老 葛,北京亚艾元软件有限责任公司,http://www.yaiyuan.com
谈到模块,就不得不提到钩子这个概念。我有时也喜欢把钩子称作钩子机制,我们可以把钩子看做Drupal的内部事件。有时也可以钩子看作是特殊的回调函数。
模块就是通过钩子,与Drupal核心系统无缝整合在一起了。钩子是一个很抽象的概念,我们通过代码来理解一下钩子机制。
function module_invoke_all() {
$args = func_get_args();
$hook = $args[0];
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;
}
代码参考地址:
http://api.drupal.org/api/drupal/includes--module.inc/function/module_invoke_all。
函数module_invoke_all是理解钩子的关键,而这里面,foreach循环中,函数module_implements是理解钩子的又一关键,它用来获取所有实现了钩子$hook的模块。而在这个循环体代码里面,第一句给出了钩子的命名规范。模块在实现钩子的时候,必须采用“模块名_钩子名”形式。其余代码的含义,就是如果这个具体的钩子函数存在(function_exists($function)),那么就调用这个钩子函数(call_user_func_array($function, $args))。
Drupal中的钩子大致可以分为3类,采用module_invoke_all调用的钩子是一类,也是最常见的;采用module_invoke调用的钩子是一类,这种钩子在Drupal核心中经常出现;还有一个就是主题钩子,比如theme_item_list,这里的item_list有时也被称为主题钩子。
上面提到了module_invoke,让我们看一下它的代码:
<?php
function module_invoke() {
$args = func_get_args();
$module = $args[0];
$hook = $args[1];
unset($args[0], $args[1]);
if (module_hook($module, $hook)) {
return call_user_func_array($module . '_' . $hook, $args);
}
}
?>
在这个函数中,call_user_func_array函数只调用了一次,而在前面的module_invoke_all函数的代码中,它被循环调用了多次。这就是两类钩子之间的区别。
有关钩子的更多信息,可以参看api.drupal.org上的在线文档,http://api.drupal.org/api/drupal/includes--module.inc/group/hooks/7。此外,如果一个模块对外提供了钩子,那么在这个模块的文件夹下面,通常会有一个modulename.api.php这样的文件,里面包含了钩子的具体说明,比如在用户模块下面,就有一个这样的文件user.api.php,里面包含了用户模块对外提供的所有钩子。