WordPress經常使用兩種鉤子,過濾鉤子和動做鉤子。過濾鉤子相關函數及源碼分析在上篇文章中完成,本篇主要分析動做鉤子源碼。數組
然而,在瞭解了動做鉤子的源碼後你會發現,動做鉤子核心代碼居然跟過濾鉤子差很少!是的,至此,我不得不告訴你,動做鉤子只是WP開發者爲了區分概念而把過濾鉤子另外命名的一種東西!固然,它們仍是有一些細微的差異,下面咱們將從源碼來深刻解讀。app
動做鉤子概念:動做鉤子是WP代碼執行到某處或某個事件發生時觸發的一系列函數,插件能夠利用動做鉤子API在WP代碼執行的特定點以前插入一系列函數以控制執行。它跟過濾鉤子極像,惟一不一樣的是過濾鉤子返回一個處理後的值,而動做鉤子僅完成函數執行並不返回值,若是鉤子不存在則返回NULL並新增該鉤子。函數
動做鉤子原理:因爲動做鉤子和過濾鉤子幾乎同樣,因此它們的實現原理也是同樣的。它主要利用一個全局變量$wp_filter,增長動做函數時使用add_action()函數給全局變量$wp_filter增長了一個數組元素,這個元素鍵名中含有鉤子名,值中含有對應函數及執行優先級等信息,在調用do_action()函數使用動做鉤子時,它經過循環查找出全部跟鉤子關聯的函數並將其依次調用,最後返回處理後的數據。源碼分析
因爲PHP代碼會通過Zend等引擎翻譯,代碼中步驟的前後順序並不重要,因此如下步驟僅爲便於理解鉤子原理的僞步驟,不具備實際參考意義!spa
一、建立鉤子(可省略):使用do_action()函數能夠建立一個沒有掛載函數的鉤子,掛載函數能夠經過add_action()添加,最後再使用do_action()調用執行;插件
二、建立動做函數:它能夠有傳入參數也能夠無傳入參數,其餘與建立普通函數沒有任何區別,函數的做用爲完成某項動做;翻譯
三、掛載函數:即便用add_action()將函數掛載到指定鉤子上;code
四、執行動做鉤子:使用do_action()能夠依次執行掛載在指定鉤子上的全部函數以完成指定任務;blog
在看動做鉤子函數做用、參數說明等時,你會發現幾乎是跟過濾鉤子重複的。至於爲何會這樣,那就要看源碼了,我保證,看完源碼後你會感慨本身被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()徹底同樣!
看過動做鉤子的源碼,是否是驚呼,原來這丫就是過濾鉤子換了個名兒而已!