WordPress强大的插件机制让我们可以自由扩展功能。网上对插件的使用以及开发方法都有大量资料可以查询。
今天我们就分析一下四个主要函数的代码,包括:
add_action、do_action、add_filter、apply_action。

一、add_action和add_filter

为什么把这两个函数放在一起讲呢?其实我们看看add_action函数的定义(图一)就可以知道,其实跟add_filter是同一个函数,执行的是相同的操作。只是把action和filter区分开,让开发者能更好地开发插件而设置的。

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

现在我们再看看add_filter的函数定义:

code
1
2
3
4
5
6
7
8
function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
    global $wp_filter, $merged_filters;
    $idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority);
    $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add,
                                              'accepted_args' => $accepted_args);
    unset( $merged_filters[ $tag ] );
    return true;
}

函数的第一行就是定义$wp_filter和$merged_filters。$wp_filter是一个多维数组,保存了目前所有的已注册在挂钩上的函数的信息。把它扩展开可以看到这样子的结构:

这里我们以两个挂钩作为例子来讲解。很明显它的结构是这样子的:

code
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
$wp_filter=array(
    '挂钩名'=>array(
        '优先级'=>array(
            '函数1'=>array(
                'function'=>"函数名",
                'accepted_args'=>"函数接受的参数数量"
            ),
            '对象'=>array(
                'function'=>array(
                    '0'=>'对象的引用',
                    '1'=>'对象上的方法'
                ),
                'accepted_args'=>"方法接受的参数数量"
            )
        )
    )
);

那么$merged_filter是什么呢?其实在这个函数里并没有体现出它的作用。但是如果我们结合do_action函数里的代码。

code
1
2
3
4
if ( !isset( $merged_filters[ $tag ] ) ) {
    ksort($wp_filter[$tag]);
    $merged_filters[ $tag ] = true;
}

我们可以知道,当相应的挂钩下的函数被调用的时候,它会对这些函数进行优先级排序,当排完序的时候,$merged_filters下对应的函数就
会被设置为true。而当我们在相应挂钩下添加一个函数的时候,它在$merged_filters数组下的值会被删除。说白了,它就是一个标识,用来说
明这个标识下的函数是否已经经过优先级排序。
我们继续分析代码。

code
1
$idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority);

这句代码里的函数我们就不展开去读了,我们只需要知道它返回的是下面这部分的内容就行了。

code
01
02
03
04
05
06
07
08
09
10
11
'函数1'=>array(
    'function'=>"函数名",
    'accepted_args'=>"函数接受的参数数量"
),
'对象'=>array(
    'function'=>array(
        '0'=>'对象的引用',
        '1'=>'对象上的方法'
    ),
    'accepted_args'=>"方法接受的参数数量"
)

接下来的这句代码也很简单,就是把函数配置到挂钩上面去而已。

code
1
$wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args);

因为这里插入了一条函数,可能改变了它下面的函数的执行优先级,所以这里的标识要删除。

code
1
unset( $merged_filters[ $tag ] );

二、do_action

函数定义:

code
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
function do_action($tag, $arg = '') {
    global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;
 
    if ( ! isset($wp_actions) )
        $wp_actions = array();
 
    if ( ! isset($wp_actions[$tag]) )
        $wp_actions[$tag] = 1;
    else
        ++$wp_actions[$tag];
 
    $wp_current_filter[] = $tag;
 
    if ( isset($wp_filter['all']) ) {
        $all_args = func_get_args();
        _wp_call_all_hook($all_args);
    }
 
    if ( !isset($wp_filter[$tag]) ) {
        array_pop($wp_current_filter);
        return;
    }
 
    $args = array();
    if ( is_array($arg) && 1 == count($arg) && isset($arg[0]) && is_object($arg[0]) ) // array(&$this)
        $args[] =& $arg[0];//参数是个数组,并且只有一个元素,并且这个元素不为空,而且是一个对象。
    else
        $args[] = $arg;
    for ( $a = 2; $a < func_num_args(); $a++ )
        $args[] = func_get_arg($a);
 
    // Sort
    if ( !isset( $merged_filters[ $tag ] ) ) {
        ksort($wp_filter[$tag]);
        $merged_filters[ $tag ] = true;
    }
 
    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);
}

第一条语句定义了几个全局函数:$wp_filter,$merged_filters,$wp_actions,$wp_current_filter。
前两个变量在前面已经做了说明了,$wp_actions是记录action被调用的次数,$wp_current_filter是记录当前使用的action的信息,它是一个堆栈结构,当出现递归调用的时候就非常有用了。
系统会先记录这个action的调用次数。然后再把当前调用的挂钩记录起来。查找有没有通用的挂钩函数,有的话就执行。接着检查有没有指定的挂钩函数,没有的话就把$wp_current_filter里相应的元素弹出,并把跳出函数返回。
如果挂钩下有相应的函数的话,那么先把要传递给函数的参数放到数组里面,再进行优先级排序,最后再一一执行。最后还是要把$wp_current_filter里相应的元素弹出。

三、apply_filter

函数定义:

code
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
function apply_filters($tag, $value) {
    global $wp_filter, $merged_filters, $wp_current_filter;
 
    $args = array();
    $wp_current_filter[] = $tag;
 
    // Do 'all' actions first
    if ( isset($wp_filter['all']) ) {
        $args = func_get_args();
        _wp_call_all_hook($args);
    }
    //如果钩子上没有这个函数,那么把函数挂到这个钩子上去。
    if ( !isset($wp_filter[$tag]) ) {
        array_pop($wp_current_filter);
        return $value;
    }
 
    // Sort 对挂钩上面的函数根据优先级进行排序,将$merged_filters[$tag]设置为真
    if ( !isset( $merged_filters[ $tag ] ) ) {
        ksort($wp_filter[$tag]);
        $merged_filters[ $tag ] = true;
    }
    //把数组指针重新定回首部
    reset( $wp_filter[ $tag ] );
    //获得参数
    if ( empty($args) )
        $args = func_get_args();
//    对挂钩上的每一个函数进行处理
    do {
        foreach( (array) current($wp_filter[$tag]) as $the_ )
            if ( !is_null($the_['function']) ){
                $args[1] = $value;
                $value = call_user_func_array($the_['function'], array_slice($args, 1,
                                              (int) $the_['accepted_args']));
            }
 
    } while ( next($wp_filter[$tag]) !== false );
 
    array_pop( $wp_current_filter );
 
    return $value;
}

仔细一看,你会发现它的代码跟do_action差不多。是的!它跟do_action有几点区别:
1、它并不记录该挂钩运行的次数。
2、由于它传入的都是一个字符串类型的参数,所以它的参数存储比较简单。
3、处理完所有函数后,会把最终处理结果返回。

reference from : http://caord.ynot.cn/?p=467

WordPress HOOK机制原理及代码分析的更多相关文章

  1. OpenStack 虚拟机冷/热迁移的实现原理与代码分析

    目录 文章目录 目录 前文列表 冷迁移代码分析(基于 Newton) Nova 冷迁移实现原理 热迁移代码分析 Nova 热迁移实现原理 向 libvirtd 发出 Live Migration 指令 ...

  2. 免费的Lucene 原理与代码分析完整版下载

    Lucene是一个基于Java的高效的全文检索库.那么什么是全文检索,为什么需要全文检索?目前人们生活中出现的数据总的来说分为两类:结构化数据和非结构化数据.很容易理解,结构化数据是有固定格式和结构的 ...

  3. SQL注入原理及代码分析(二)

    前言 上一篇文章中,对union注入.报错注入.布尔盲注等进行了分析,接下来这篇文章,会对堆叠注入.宽字节注入.cookie注入等进行分析.第一篇文章地址:SQL注入原理及代码分析(一) 如果想要了解 ...

  4. XSS原理及代码分析

    前言 XSS又叫跨站脚本攻击,是一种对网站应用程序的安全漏洞攻击技术.它允许恶意用户将代码注入网页,其他用户在浏览网页时就会受到影响.XSS分为三种:反射型,存储型,和DOM型.下面我会构造有缺陷的代 ...

  5. lighttpd与fastcgi+cgilua原理、代码分析与安装

    原理 http://www.cnblogs.com/skynet/p/4173450.html 快速通用网关接口(Fast Common Gateway Interface/FastCGI)是通用网关 ...

  6. SQL注入原理及代码分析(一)

    前言 我们都知道,学安全,懂SQL注入是重中之重,因为即使是现在SQL注入漏洞依然存在,只是相对于之前现在挖SQL注入变的困难了.而且知识点比较多,所以在这里总结一下.通过构造有缺陷的代码,来理解常见 ...

  7. AbstractQueuedSynchronizer原理及代码分析

    一.AQS简介 AbstractQueuedSynchronizer(AQS)是java.util.concurrent并发包下最基本的同步器,其它同步器实现,如ReentrantLock类,Reen ...

  8. drone的pipeline原理与代码分析

    最近的一个项目,需要实现一个工作任务流(task pipeline),基于之前CICD的经验,jenkins pipeline和drone的pipeline进入候选. drone是基于go的cicd解 ...

  9. Openvswitch原理与代码分析(1):总体架构

      一.Opevswitch总体架构   Openvswitch的架构网上有如下的图表示:       每个模块都有不同的功能 ovs-vswitchd 为主要模块,实现交换机的守护进程daemon ...

随机推荐

  1. Geoserver发布WMS服务出错分析

    使用Geoserver发布一个空间表,在图层预览的过程中没有任何问题,但是当我根据这个空间表传创建视图再发布wms服务,访问时就会报错,错误信息如下: Caused by: java.sql.SQLE ...

  2. NOI2016 山西省省选 第二题序列

    给出一个n(n<=10^18)然后把n拆成若干个数之和(3=1+2=2+1 是两种情况) 然后把这写数字当作斐波那契数列的下标相乘再相加 例如: 3=1+1+1=1+2=2+1=3 所以结果就是 ...

  3. 【MVC 4】5.SportsSore —— 一个真实的应用程序

     作者:[美]Adam Freeman      来源:<精通ASP.NET MVC 4> 前面建立的都是简单的MVC程序,现在到了吧所有事情综合在一起,以建立一个简单但真实的电子商务应用 ...

  4. 广搜+打表 POJ 1426 Find The Multiple

    POJ 1426   Find The Multiple Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 25734   Ac ...

  5. 一致性哈希算法学习及JAVA代码实现分析

    1,对于待存储的海量数据,如何将它们分配到各个机器中去?---数据分片与路由 当数据量很大时,通过改善单机硬件资源的纵向扩充方式来存储数据变得越来越不适用,而通过增加机器数目来获得水平横向扩展的方式则 ...

  6. HDU 4122 Alice's mooncake shop --RMQ

    题意: 一个月饼店做月饼,总营业时间m小时,只能在整点做月饼,可以做无限个,不过在不同的时间做月饼的话每个月饼的花费是不一样的,假设即为cost[i],再给n个订单,即为在某个时间要多少个月饼,时间从 ...

  7. Git版本控制工具(三)----远程仓库GitHub的使用

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  8. AutoIT简介

    AutoIT最初是为了帮助IT管理和维护而开发的工具,能自动完成软件的安装.由于自动化安装和自动化测试在功能需求上有许多相似之处,都要模拟用户对软件进行操作,并验证执行的结果,所以,AutoIT逐渐成 ...

  9. Fidder--实现手机的抓包

    今天闲着没吊事,来写一篇关于怎么抓取Android中的app数据包?工欲行其事,必先利其器,上网google了一下,发现了一款神器:Fiddler,这个貌似是所有软件开发者必备神器呀!这款工具不仅可以 ...

  10. 003医疗项目-关于<context:property-placeholder location="classpath:db.properties"/>的问题

    项目结构如下: