黄聪:WordPress动作钩子函数add_action()、do_action()源码解析

WordPress常用两种钩子,过滤钩子和动作钩子。过滤钩子相关函数及源码分析在上篇文章中完成,本篇主要分析动作钩子源码。

然而,在了解了动作钩子的源码后你会发现,动作钩子核心代码竟然跟过滤钩子差不多!是的,至此,我不得不告诉你,动作钩子只是WP开发者为了区分概念而把过滤钩子另外命名的一种东西!当然,它们还是有一些细微的差别,下面我们将从源码来深入解读。

动作钩子概念:动作钩子是WP代码执行到某处或某个事件发生时触发的一系列函数,插件可以利用动作钩子API在WP代码执行的特定点之前插入一系列函数以控制执行。它跟过滤钩子极像,唯一不同的是过滤钩子返回一个处理后的值,而动作钩子仅完成函数执行并不返回值,如果钩子不存在则返回NULL并新增该钩子。

动作钩子原理:由于动作钩子和过滤钩子几乎一样,所以它们的实现原理也是一样的。它主要利用一个全局变量$wp_filter,增加动作函数时使用add_action()函数给全局变量$wp_filter增加了一个数组元素,这个元素键名中含有钩子名,值中含有对应函数及执行优先级等信息,在调用do_action()函数使用动作钩子时,它通过循环查找出所有跟钩子关联的函数并将其依次调用,最后返回处理后的数据。

 

动作钩子使用步骤

由于PHP代码会经过Zend等引擎翻译,代码中步骤的先后顺序并不重要,所以以下步骤仅为便于理解钩子原理的伪步骤,不具有实际参考意义!

1、创建钩子(可省略):使用do_action()函数可以创建一个没有挂载函数的钩子,挂载函数可以通过add_action()添加,最后再使用do_action()调用执行;

2、创建动作函数:它可以有传入参数也可以无传入参数,其他与创建普通函数没有任何区别,函数的作用为完成某项动作;

3、挂载函数:即使用add_action()将函数挂载到指定钩子上;

4、执行动作钩子:使用do_action()可以依次执行挂载在指定钩子上的所有函数以完成指定任务;

动作钩子函数详解:

在看动作钩子函数作用、参数说明等时,你会发现几乎是跟过滤钩子重复的。至于为什么会这样,那就要看源码了,我保证,看完源码后你会感慨自己被WP开发者涮了!

1、add_action($tag,$function_to_add,$priority = 10,$accepted_args = 1)

add_action()作用:该函数用于给指定的动作钩子$tag添加指定的挂载函数$function_to_add,同时它可以确定挂载函数执行优先级及其可接收参数个数;

add_action()参数说明

$tag为钩子名;

$function_to_add为挂载函数名;

可选参数$priority为该挂载函数执行的优先级,默认为10,该数字越小则越早执行,数字相同则按其添加到钩子上的顺序执行,越早添加越早执行;

可选参数$accepted_args确定挂载函数接收的参数个数,默认为1;

add_action()源码分析:

function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
    return add_filter($tag, $function_to_add, $priority, $accepted_args);
}

怎么样,看到了吧!被坑了有木有!add_action()函数的代码竟然是调用一次add_filter()!这尼玛完全是一个人的大名和小名的问题有木有!

2、do_action($tag, $arg = ‘‘)

do_action()作用:该函数调用挂载在过滤钩子$tag上的所有函数以完全特定的任务;

do_action()参数说明:

$tag为钩子名;

$arg为动作钩子上挂载函数的传入参数,默认为空;

do_action()源码分析:

function do_action($tag, $arg = ‘‘) {
    global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;
    if ( ! isset($wp_actions) )
        $wp_actions = array();
# 如果$wp_actions变量未设置过,则将其定义为数组;
    if ( ! isset($wp_actions[$tag]) )
        $wp_actions[$tag] = 1;
    else
        ++$wp_actions[$tag];
    # 如果$wp_actions[$tag]未设置则将其赋值为1,否则将其值加1;
    if ( isset($wp_filter[‘all‘]) ) {
        $wp_current_filter[] = $tag;
        $all_args = func_get_args();
        _wp_call_all_hook($all_args);
    }
    # 跟apply_filters()中的all钩子处理方式完全一样!_wp_call_all_hook()源码分析见上篇文章过滤钩子源码解析;
    if ( !isset($wp_filter[$tag]) ) {
        if ( isset($wp_filter[‘all‘]) )
            array_pop($wp_current_filter);
        return;
    }
    # 当前钩子不存在,则直接返回,不再执行以后代码;
    if ( !isset($wp_filter[‘all‘]) )
        $wp_current_filter[] = $tag;
    # 将当前钩子设置为$tag;
    $args = array();
    if ( is_array($arg) && 1 == count($arg) && isset($arg[0]) && is_object($arg[0]) )
        $args[] =& $arg[0];
    else
        $args[] = $arg;
    # do_action()若有传入参数,且为一个数组,该数组仅此一个元素,该元素有值则将$args值设置为引用$arg[0],否则直接赋值;
    for ( $a = 2; $a < func_num_args(); $a++ )
        $args[] = func_get_arg($a);
    # 通过for循环,若do_action()有不只一个传入参数,将这些值赋给数组$args;
    if ( !isset( $merged_filters[ $tag ] ) ) {
        ksort($wp_filter[$tag]);
        $merged_filters[ $tag ] = true;
    }
    # 跟apply_filter()函数排序代码完全一样!详解见上文;
    reset( $wp_filter[ $tag ] );
    do {
        foreach ( (array) current($wp_filter[$tag]) as $the_ )
            if ( !is_null($the_[‘function‘]) )
                call_user_func_array($the_[‘function‘], array_slice($args, 0, (int) $the_[‘accepted_args‘]));
    } while ( next($wp_filter[$tag]) !== false );
    array_pop($wp_current_filter);
}
    # 除了少了一行return $value其他跟apply_filters()完全一样!

看过动作钩子的源码,是不是惊呼,原来这丫就是过滤钩子换了个名儿而已!

时间: 2024-10-18 18:23:32

黄聪:WordPress动作钩子函数add_action()、do_action()源码解析的相关文章

二.jQuery源码解析之构建jQuery之构建函数jQuery的7种用法

一:$(selectorStr[,限制范围]),接受一个选择器(符合jQuery规范的字符串),返回一个jQuery对象;二:$(htmlStr[,文档对象]),$(html[,json对象])传入html字符串,创建一个新的dom元素 三:$(dom元素),$(dom元素集合)将dom元素转换成jQuery对象.四:$(自定义对象)封装普通对象为jQuery对象.五:$(回调函数)绑定ready事件监听函数,当Dom加载完成时执行.六:$(jQuery对象)接受一个jQuery对象,返回一个j

co函数库源码解析

一.co函数是什么 co 函数库是著名程序员 TJ Holowaychuk 于2013年6月发布的一个小工具,用于 Generator 函数的自动执行.短小精悍只有短短200余行,就可以免去手动编写Generator 函数执行器的麻烦 二.co函数怎么用 举个栗子就能清楚的知道如何使用co函数 1 function* gen(){ 2 var f1 = yield func1; 3 var f2 = yield fnuc2; 4 //sth to do 5 }; 手动执行和co函数执行的写法如下

jQuery 源码解析(八) 异步队列模块 Callbacks 回调函数详解

异步队列用于实现异步任务和回调函数的解耦,为ajax模块.队列模块.ready事件提供基础功能,包含三个部分:Query.Callbacks(flags).jQuery.Deferred(funct)和jQuery.when().本节讲解Callbacks,也就是回调函数列表 回调函数用于管理一组回调函数,支持添加.移除.触发.锁定和禁用回调函数,为jQuery.ajax.jQuery.Deferred()和ready()事件提供基础功能,我们也可以基于它编写新的组件. 使用方法:$.Callb

黄聪:wordpress源码解析-数据库表结构(转)

如果是一个普通的用户,不需要了解wordpress数据库的结构.但是,如果你正在写一个插件,你应该会对wordpress如何处理它的数据和关系感兴趣.如果你已经尝试使用已经存在的wordpress api 去访问你需要的数据,但不直接访问数据库的情况下,这是不可能的,WordPress的提供WPDB的类,使这项任务变得简单. WordPress数据库的11个数据表分别是: 表名(点击表名查看详细介绍) 描述 wp_commentmeta 文章评论额外信息表 wp_comments 文章评论信息表

黄聪:wordpress源码解析-目录结构-文件调用关系(转)

Wordpress是一个单入口的文件,所有的前端处理都必须经过index.php,这是通过修改web服务器的rewrite规则来实现的.这种做法的好处是显而易见的,这样URL更好看,不必为每一个url新建一个文件. 我们看看wp大致的文件调用是什么样子的. wordpress可以分为3个阶段,一是初始化阶段,即初始化常量.环境.加载核心文件等等:二是内容处理阶段,即根据用户的请求调用相关函数获取和处理数据,为前端展示准备数据:三是主题应用阶段,在这个阶段,需要展示的数据已经准备完毕,需要根据用户

wordpress源码解析-数据库表结构(转)

如果是一个普通的用户,不需要了解wordpress数据库的结构.但是,如果你正在写一个插件,你应该会对wordpress如何处理它的数据和关系感兴趣.如果你已经尝试使用已经存在的wordpress api 去访问你需要的数据,但不直接访问数据库的情况下,这是不可能的,WordPress的提供WPDB的类,使这项任务变得简单. WordPress数据库的11个数据表分别是: 表名(点击表名查看详细介绍) 描述 wp_commentmeta 文章评论额外信息表 wp_comments 文章评论信息表

underscore.js源码解析【函数】

// Function (ahem) Functions // ------------------ // Determines whether to execute a function as a constructor // or a normal function with the provided arguments. /* 判断一个函数是按照构造函数还是普通函数执行?????????????????????????????????????????????????????????? */

OBS源码解析(1)main函数

int main(int argc, char *argv[]){#ifndef _WIN32 signal(SIGPIPE, SIG_IGN);#endif #ifdef _WIN32 /*OpenProcessToken函数用来打开与进程相关联的访问令牌,设置crash处理句柄*/ load_debug_privilege(); base_set_crash_handler(main_crash_handler, nullptr);#endif /*初始化log句柄*/ base_get_l

C语言基础:数组作为函数参数传递演示源码

将做工程过程中常用的内容片段记录起来,如下内容内容是关于C语言基础:数组作为函数参数传递演示的内容,应该能对小伙伴也有好处. #include <stdio.h> void show_array(int values[], int number_of_elements) { int i; printf("About to display %d valuesn", number_of_elements); for (i = 0; i < number_of_elemen