Drupal的不少功能都是能夠定製的。以導航菜單爲例,blog模塊須要在菜單上添加一些功能,comment模塊須要在菜單上添加一些功能,咱們開發的自定義模塊也須要在菜單上添加一些功能。Drupal開發者爲了達到這樣的擴展目的,設計了鉤子系統,導航菜單就是其中一個名爲menu的鉤子。有了鉤子系統,開發人員就能夠在blog模塊定義一個鉤子函數從而實現menu鉤子。Drupal要求鉤子函數的命名必需要求以模塊名開始,以鉤子名爲後綴。less
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文件裏面,而不用都擠在模塊主文件。oop
module_implements()函數返回實現某個鉤子的全部函數,它用module_list()遍歷當前激活的所喲模塊:ui
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鉤子系統的最外層接口:this
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()就能夠了:spa
$items = module_invoke_all('menu');