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
转载于:https://www.cnblogs.com/zhangchenliang/p/4000153.html