WordPress HOOK机制原理及代码分析
WordPress强大的插件机制让我们可以自由扩展功能。网上对插件的使用以及开发方法都有大量资料可以查询。
今天我们就分析一下四个主要函数的代码,包括:
add_action、do_action、add_filter、apply_action。
一、add_action和add_filter
为什么把这两个函数放在一起讲呢?其实我们看看add_action函数的定义(图一)就可以知道,其实跟add_filter是同一个函数,执行的是相同的操作。只是把action和filter区分开,让开发者能更好地开发插件而设置的。
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的函数定义:
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是一个多维数组,保存了目前所有的已注册在挂钩上的函数的信息。把它扩展开可以看到这样子的结构:
这里我们以两个挂钩作为例子来讲解。很明显它的结构是这样子的:
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函数里的代码。
1
2
3
4
|
if ( !isset( $merged_filters [ $tag ] ) ) { ksort( $wp_filter [ $tag ]); $merged_filters [ $tag ] = true; } |
我们可以知道,当相应的挂钩下的函数被调用的时候,它会对这些函数进行优先级排序,当排完序的时候,$merged_filters下对应的函数就
会被设置为true。而当我们在相应挂钩下添加一个函数的时候,它在$merged_filters数组下的值会被删除。说白了,它就是一个标识,用来说
明这个标识下的函数是否已经经过优先级排序。
我们继续分析代码。
1
|
$idx = _wp_filter_build_unique_id( $tag , $function_to_add , $priority ); |
这句代码里的函数我们就不展开去读了,我们只需要知道它返回的是下面这部分的内容就行了。
01
02
03
04
05
06
07
08
09
10
11
|
'函数1' => array ( 'function' => "函数名" , 'accepted_args' => "函数接受的参数数量" ), '对象' => array ( 'function' => array ( '0' => '对象的引用' , '1' => '对象上的方法' ), 'accepted_args' => "方法接受的参数数量" ) |
接下来的这句代码也很简单,就是把函数配置到挂钩上面去而已。
1
|
$wp_filter [ $tag ][ $priority ][ $idx ] = array ( 'function' => $function_to_add , 'accepted_args' => $accepted_args ); |
因为这里插入了一条函数,可能改变了它下面的函数的执行优先级,所以这里的标识要删除。
1
|
unset( $merged_filters [ $tag ] ); |
二、do_action
函数定义:
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
函数定义:
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机制原理及代码分析的更多相关文章
- OpenStack 虚拟机冷/热迁移的实现原理与代码分析
目录 文章目录 目录 前文列表 冷迁移代码分析(基于 Newton) Nova 冷迁移实现原理 热迁移代码分析 Nova 热迁移实现原理 向 libvirtd 发出 Live Migration 指令 ...
- 免费的Lucene 原理与代码分析完整版下载
Lucene是一个基于Java的高效的全文检索库.那么什么是全文检索,为什么需要全文检索?目前人们生活中出现的数据总的来说分为两类:结构化数据和非结构化数据.很容易理解,结构化数据是有固定格式和结构的 ...
- SQL注入原理及代码分析(二)
前言 上一篇文章中,对union注入.报错注入.布尔盲注等进行了分析,接下来这篇文章,会对堆叠注入.宽字节注入.cookie注入等进行分析.第一篇文章地址:SQL注入原理及代码分析(一) 如果想要了解 ...
- XSS原理及代码分析
前言 XSS又叫跨站脚本攻击,是一种对网站应用程序的安全漏洞攻击技术.它允许恶意用户将代码注入网页,其他用户在浏览网页时就会受到影响.XSS分为三种:反射型,存储型,和DOM型.下面我会构造有缺陷的代 ...
- lighttpd与fastcgi+cgilua原理、代码分析与安装
原理 http://www.cnblogs.com/skynet/p/4173450.html 快速通用网关接口(Fast Common Gateway Interface/FastCGI)是通用网关 ...
- SQL注入原理及代码分析(一)
前言 我们都知道,学安全,懂SQL注入是重中之重,因为即使是现在SQL注入漏洞依然存在,只是相对于之前现在挖SQL注入变的困难了.而且知识点比较多,所以在这里总结一下.通过构造有缺陷的代码,来理解常见 ...
- AbstractQueuedSynchronizer原理及代码分析
一.AQS简介 AbstractQueuedSynchronizer(AQS)是java.util.concurrent并发包下最基本的同步器,其它同步器实现,如ReentrantLock类,Reen ...
- drone的pipeline原理与代码分析
最近的一个项目,需要实现一个工作任务流(task pipeline),基于之前CICD的经验,jenkins pipeline和drone的pipeline进入候选. drone是基于go的cicd解 ...
- Openvswitch原理与代码分析(1):总体架构
一.Opevswitch总体架构 Openvswitch的架构网上有如下的图表示: 每个模块都有不同的功能 ovs-vswitchd 为主要模块,实现交换机的守护进程daemon ...
随机推荐
- 边工作边刷题:70天一遍leetcode: day 84-2
要点:这题是combination的应用,从左向右想比从右向左容易. 因为有结果从小到大的要求,暗示用combintion而不是permutation 其实就是从小到大验证因子,每个因子和其对称因子立 ...
- codeforces 709B B. Checkpoints(水题)
题目链接: B. Checkpoints 题意: 给了n个点,现在给一个起点,问最少访问n-1个点的最小行走距离是多少; 思路: 分情况讨论就好了; AC代码: #include <iostre ...
- swfobject.js视频播放插件
在网页中经常会用到视频播放的功能,下面介绍一下swfobject.js的视频播放应用:html代码结构: <div id="video_content"></di ...
- 深入.NET框架 项目《魔兽登录系统》
创建魔兽系统相关窗体: 登录窗体(frmLogin) 注册窗体(frmRegister) 主窗体 (frmMain) 实现魔兽登录系统: 登录的界面如下 实现思路: 1.创建一个对象数组,长度为1 ...
- PPP(点对点协议(Point to Point Protocol)
1.简介PPP(点到点协议)是为在同等单元之间传输数据包这样的简单链路设计的链路层协议.这种链路提供全双工操作,并按照顺序传递数据包.设计目的主要是用来通过拨号或专线方式建立点对点连接发送数据,使其成 ...
- Hibernate出现javax.naming.NoInitialContextException 错误的解决办法
异常信息: 08:02:56,329 WARN SessionFactoryObjectFactory:123 - Could not unbind factory from JNDI javax.n ...
- setAttribute改变属性,动态改变类
<style type="text/css"> .box{color:red;} </style> <div>通过setAttribute添加d ...
- 第三章 Models模块属性详解
摘自:http://www.cnblogs.com/xdotnet/archive/2012/03/07/aspnet_mvc40_validate.html 了解了这些就可以对MVC进一步认识,相信 ...
- cookies,sessionStorage和localStorage的区别
联系: sessionStorage和localStorage一样,都是用来缓存客户端缓存信息. 他们都只能存储字符串类型对象. 区别: localStorage的生命周期是永久的,除非用户主动清除浏 ...
- MySQL学习指引
mysql指引 1,mysql基本安装 2,mysql多实例安装与维护 3,备份恢复 备份数据库 分备数据库 分备表 恢复数据库