Hook机制里登场的角色
2015-07-14 08:03
309 查看
稍有接触过WordPress主题或插件制作修改的朋友,对WordPress的Hook机制应该不陌生,但通常刚接触WordPressHook的新手,对其运作原理可能会有点混乱或模糊。本文针对WordPressHook运作大致做个简单的说明,而预设读者是理解基本的PHPfunction语法及运作,但对WordPressHook机制不是很明白。
因此若没有针对此Hook去“加入”要钩上去的HookFunction,执行到此什么也不会做。因此,它等于是WordPress核心预留一个执行的机会给未来想要加入定制功能的开发者。
请看下面的情境示例图,我们把wp_head及wp_footer看成是”钩子“,而别的hookfunctions就能来鈎住它:
我们马上来写一个简单的例子。我们要写一个hookfunction,就叫它print_sth(),然後把它钩上wp_head这个hook。因为wp_head()的内容实际上就只有do_action('wp_head');这一行内容,而wp_footer()的内容也只有do_action('wp_footer');所以我们直接把do_action的语法换到图上去,比较容易做说明,因此示意图变成:
如此,只要执行到输出header.php时,就会执行到wp_head(),就如同执行到do_action('wp_head');此时WP核心会去找所有”钩上”wp_head这个hook的hookfunction,於是就找到我们写的print_sth(),然後就执行它,所以结果它做的事就会出现在网站上,也完成了”定制”的动作:
简单的说,Hook机制就是:WP核心或其他插件、主题提供想定制功能的人一个置入定制程式码(HookFunction)到特定的执行时间点(Hook)的机会。
WP核心做它该做的事,你做你想做的事,做完就各自结束。
透过你的干涉,修改了WP核心丢给你的参数,WP核心再接着拿你改过的参数,继续完成它该做的事,此动作就像”过滤“的动作,因而得名filter。
然后我们可以在某处(可能是其他插件、functions.php等处,要”实现定制功能“的地方)添加对应的hookfunction:
所以其实两种Hook的运作方式几乎一样,只差在增加ActionHook函式不需回传值,而增加FilterHookfunction时,你必须要回传一个值。所以FilterHook函式通常都有提供参数,让想定制的人可以取得它,处理后再回传。
但如果有一个FilterHook,它没有任何hookfunction有去钩它,它该怎么取得回传值?答案是,直接拿第一个它给的参数,以上面的例子来说,它会直接拿$a丢进$c。另外,其实我们也可以把filter写的跟action一样,只要不回传值就行,但actionhook就没办法”模仿“filterhook,因为无法取得回传值。
就像我们刚才说明的例子中,我们使用add_filter加入special_func时设定的优先序是10,这也是Priority参数的预设值。如果你希望它能优先被执行,就设定小于10的数字,反之,就设个100、500之类的,让它延后被执行。
但其实这里有个隐含的冲突问题。
以wp_head这个hook为例,如果我写了一个插件,希望透过wp_head来输出”增加a.css档案“的HTML语法,而a.css会重新设定body元素的样式,所以我希望它可以最后才被汇入,不要被其他css档干扰,于是我将Priority设为900,但我怎么知道Priority900够不够大?若某个WP网站,它除了安装我的插件,也安装了其他插件,而其他插件刚好也重新设定body元素的样式,然后把Priority设为950,此时我写的插件在处理body样式时就出事了,于是就跟其他插件冲突了。
所以此时我们需要了解的是:我的WP网站可能装了很多插件,我怎么知道同一个Hook被加了多少HookFunction,而每个HookFunction的Priority被设定为多少?
答案是,我们可以透过$wp_filters这个global变数来取得所有hook的信息,像是如下的function:
当我们呼叫list_hooked_functions('wp_head');时,就会列出wp_head这个Hook所钩住的所有hookfunction,可以看到priority10之后有好几个都没有数字,因为它们都没有特别指定priority,所以都是10,包括我们刚才写的print_sth也在其中:
>>>>>wp_head
1wp_enqueue_scripts
2feed_links
3feed_links_extra
8wp_print_styles
9wp_print_head_scripts
10rsd_link
wlwmanifest_link
index_rel_link
parent_post_rel_link
start_post_rel_link
adjacent_posts_rel_link_wp_head
locale_stylesheet
wp_generator
rel_canonical
wp_shortlink_wp_head
print_sth
wp_admin_bar_header
_admin_bar_bump_cb
Hook机制里登场的角色
先从“登场角色”的个别说明开始:WordPress核心
指的是WordPress内建的程式码架构,提供WordPress主要的基本功能。Hook
也许你早已听说,Hook本身虽是钩子的意思,但直译又有点奇怪,所以一般通常都不直译它,而是直接称它Hook。WordPress的Hook也可以想像成“钩子”,这些“钩子”会埋在WordPress网站中特定几处的程式码中,埋进去时使用的语法,其“标示位置”的意义比较大,没有实质运作的内容。当程式执行到有埋Hook的地方时,它会找出所有对应到自己的HookFunction(也就是所有“钩到”该Hook的hookfunction),并一一执行。因此若没有针对此Hook去“加入”要钩上去的HookFunction,执行到此什么也不会做。因此,它等于是WordPress核心预留一个执行的机会给未来想要加入定制功能的开发者。
HookFunction
HookFunction里会有实质运作的内容,即是实作了一些定制功能,可能是存取DB、增加HTMLcode、执行其他函式等等。我们在HookFunction里写好所需的功能后,就可以利用“加入至对应Hook”的语法,把HookFunction自已钩到该Hook上,使得该Hook被执行到时,也会连带执行自己。Hook机制是如何运作的?
举个例子,我们拿wp_head及wp_footer这两个内建的hook来说明,wp_head这个hook就是用来埋在负责输出标签的程式码中,而wp_footer就是用来埋在输出页尾的程式码中(定义于wp-includes/general-template.php,用wp_head()及wp_footer()包装起来)。这两个hook,主要都是在布景档案中使用的,常见会出现在header.php及footer.php中。请看下面的情境示例图,我们把wp_head及wp_footer看成是”钩子“,而别的hookfunctions就能来鈎住它:
我们马上来写一个简单的例子。我们要写一个hookfunction,就叫它print_sth(),然後把它钩上wp_head这个hook。因为wp_head()的内容实际上就只有do_action('wp_head');这一行内容,而wp_footer()的内容也只有do_action('wp_footer');所以我们直接把do_action的语法换到图上去,比较容易做说明,因此示意图变成:
如此,只要执行到输出header.php时,就会执行到wp_head(),就如同执行到do_action('wp_head');此时WP核心会去找所有”钩上”wp_head这个hook的hookfunction,於是就找到我们写的print_sth(),然後就执行它,所以结果它做的事就会出现在网站上,也完成了”定制”的动作:
简单的说,Hook机制就是:WP核心或其他插件、主题提供想定制功能的人一个置入定制程式码(HookFunction)到特定的执行时间点(Hook)的机会。
WordPress的ActionHook与FilterHook
WordPress中的Hook有两种,分别是”ActionHook“及”FilterHook“,我们刚才举例的wp_head及wp_footer都是属於ActionHook。不过,一开始你可以先把这两种Hook看成是一样的东西,只是Filter多了一点点不同的特色,接着说明。ActionHook
WP核心(或主题、插件)在做它们该做的事时,如果执行到有埋actionhook的程式码(即是do_action语法)时,会去找寻对应到的hookfunctions,进而执行这些hookfunctions(即那些透过add_action()来加入的hookfunctions),藉此完成定制功能。WP核心并不期待ActionHookfunctions会有回传值,所以这里的hookfunction只被视为一个”独立切出来运作的功能“。WP核心做它该做的事,你做你想做的事,做完就各自结束。
FilterHook
跟ActionHook一样,WP核心(或主题、插件)在做它们该做的事时,如果执行到有埋filterhook的程式码(即是apply_filters语法)时,就会去找寻对应的hookfunctions,进而执行这些hookfunctions(即那些透过add_filter()来加入的hookfunctions),藉此完成定制功能。与ActionHook不同之处是,所有”鈎上“FilterHook的hookfunctions通常都会接收到参数,而WP核心会期待你拿到它提供的参数,并做完你想做的事后,要回传(return)一个值,让WP核心再利用你回传的值来接着完成它该做的事。透过你的干涉,修改了WP核心丢给你的参数,WP核心再接着拿你改过的参数,继续完成它该做的事,此动作就像”过滤“的动作,因而得名filter。
比较ActionHook与FilterHook的操作语法
比较一下两种Hook在埋进某处程式码时所用的语法,假设我们在某处(可能是在输出页首的程式码处,或输出文章标题、文章内容、侧边栏…等地方,要”出现定制效果“的地方)埋下这两种hook:/*---------------ActionHook---------------*/
//埋下一个名叫'do_more'的actionhook
do_action('do_more');
/*---------------FilterHook---------------*/
//埋下一个名叫'get_special'的filterhook,注意它会有回传值
$c=apply_filters('get_special',$a,$b);
然后我们可以在某处(可能是其他插件、functions.php等处,要”实现定制功能“的地方)添加对应的hookfunction:
/*---------------ActionHookFunction---------------*/
//增加要钩上'do_more'这个hook的hookfunction,
//并为此hookfunction取名叫more_func。
//第一个参数是hook名称、第二个是hookfunction名称
add_action('do_more','more_func');
//添加more_func的內容,不需回传值
functionmore_func()
{
echo'domorething...';
}
/*---------------FilterHookFunction---------------*/
//增加要钩上'get_special'hook的hookfunction,
//并为此hookfunction取名叫special_func。
//参数1是hook名称、参数2是hookfunction名称
//参数3是Priority(优先序)、参数4是hookfunction参数的数目
add_filter('get_special','special_func',10,2);
//添加special_func的內容,需要給它回传值
functionspecial_func($a,$b)
{
$c=$a.'&'.$b;//做一些事,例如把两个参数连接起來
return$c;//回传值
}
所以其实两种Hook的运作方式几乎一样,只差在增加ActionHook函式不需回传值,而增加FilterHookfunction时,你必须要回传一个值。所以FilterHook函式通常都有提供参数,让想定制的人可以取得它,处理后再回传。
但如果有一个FilterHook,它没有任何hookfunction有去钩它,它该怎么取得回传值?答案是,直接拿第一个它给的参数,以上面的例子来说,它会直接拿$a丢进$c。另外,其实我们也可以把filter写的跟action一样,只要不回传值就行,但actionhook就没办法”模仿“filterhook,因为无法取得回传值。
HookFunction的优先序(Priority)
如果有很多地方(主题或者插件的functions.php)都添加同一个hook,会怎么决定出现顺序?答案很显然是可以透过HookFunction的Priority参数来作优先序的设定:就像我们刚才说明的例子中,我们使用add_filter加入special_func时设定的优先序是10,这也是Priority参数的预设值。如果你希望它能优先被执行,就设定小于10的数字,反之,就设个100、500之类的,让它延后被执行。
但其实这里有个隐含的冲突问题。
以wp_head这个hook为例,如果我写了一个插件,希望透过wp_head来输出”增加a.css档案“的HTML语法,而a.css会重新设定body元素的样式,所以我希望它可以最后才被汇入,不要被其他css档干扰,于是我将Priority设为900,但我怎么知道Priority900够不够大?若某个WP网站,它除了安装我的插件,也安装了其他插件,而其他插件刚好也重新设定body元素的样式,然后把Priority设为950,此时我写的插件在处理body样式时就出事了,于是就跟其他插件冲突了。
所以此时我们需要了解的是:我的WP网站可能装了很多插件,我怎么知道同一个Hook被加了多少HookFunction,而每个HookFunction的Priority被设定为多少?
答案是,我们可以透过$wp_filters这个global变数来取得所有hook的信息,像是如下的function:
//列出所有的hookfunction及其priority
functionlist_hooked_functions($tag=false)
{
global$wp_filter;
if($tag)
{
$hook[$tag]=$wp_filter[$tag];
if(!is_array($hook[$tag]))
{
trigger_error("Nothingfoundfor'$tag'hook",E_USER_WARNING);
return;
}
}
else
{
$hook=$wp_filter;
ksort($hook);
}
echo'<pre>';
foreach($hookas$tag=>$priority)
{
echo"<br/>>>>>>\t<strong>$tag</strong><br/>";
ksort($priority);
foreach($priorityas$priority=>$function)
{
echo$priority;
foreach($functionas$name=>$properties)echo"\t$name<br/>";
}
}
echo'</pre>';
return;
}
当我们呼叫list_hooked_functions('wp_head');时,就会列出wp_head这个Hook所钩住的所有hookfunction,可以看到priority10之后有好几个都没有数字,因为它们都没有特别指定priority,所以都是10,包括我们刚才写的print_sth也在其中:
>>>>>wp_head
1wp_enqueue_scripts
2feed_links
3feed_links_extra
8wp_print_styles
9wp_print_head_scripts
10rsd_link
wlwmanifest_link
index_rel_link
parent_post_rel_link
start_post_rel_link
adjacent_posts_rel_link_wp_head
locale_stylesheet
wp_generator
rel_canonical
wp_shortlink_wp_head
print_sth
wp_admin_bar_header
_admin_bar_bump_cb
所以,冲突很难提早避免,但发生冲突时,可以预先思考有没有可能是因为priority的设定,导致结果跟预期不符合。
原文出自:
相关文章推荐
- J2EE学习笔记
- 锁升级
- Cisco NX-OS与Cisco IOS对比
- 右拐角矩阵
- PDO防注入原理分析以及注意事项
- 新建jsp出现问题
- .NET平台开源项目速览(10)FluentValidation验证组件深入使用(二)
- WCF初探-28:WCF中的并发
- OGG问题诊断和性能优化工具
- Juniper SSG5(bgroupx接口详解及删除bgroupx自定义)
- Delphi 中控件路径添加不进去解决方法
- Goldengate Monitor Introduction
- 【剑指Offer学习】【面试题63:二叉搜索树的第k个结点】
- 弱弱的碎碎念---一个股市老兵的只言片语
- Goldengate重新同步单个表
- 穿越牛梦 未雨绸缪
- HTTP请求方式
- Goldengate Directory Repository迁移
- Codility 算法测验(四)
- HTTP 错误 500.21 - Internal Server Error