1. 程式人生 > >鉤子系統原理及ThinkPHP 鉤子分析

鉤子系統原理及ThinkPHP 鉤子分析

鉤子系統,乍一看,好高大上,讓人摸不到頭腦。其實,大多技術或者方案,它總要起個名字,要是瞭解了其原理,這個名字其實也不必糾結。以下都是個人觀點:

首先,我們來一段php程式碼:

<?php
	function deleteData(){
		echo 'Deleting data! ...';
	}

	function addData(){
		echo 'Adding data! ...';
	}
		
	if(isset($_GET['act']) && $_GET['act'] == 'delete'){
		$funcName = 'deleteData';
	}else{
		$funcName = 'addData';
	}
	$funcName();
?>
看到這裡,會發現,咦,程式碼還可以這樣寫?是的,php允許通過變數呼叫函式。

好吧,再來看一段jQuery程式碼:

$(function(){
	$("#clicked_me").click(function(e){
		console.log("I'm clicked! ...");
	});	
});
上面的程式碼很容易理解,cliecked_me元素被點選的時候,在控制檯輸輸出:I'm clicked! ...

到這裡,可以發現:原來有些程式碼,是可以在某些特定的時間被呼叫(執行)的,其實,這叫“事件驅動”。

ok,再來一段php程式碼:

        $callback = function(){
		echo 'Calling back! ...<br/>';
	};

	function func($cb){
		echo 'A function named "func" was been calling! ...<br/>';
		$cb();
	}

	func($callback);

是的,函式也可以作為另一個函式的引數被傳遞,然後通過形參這個變數,呼叫函式。

好吧,你知道的,我又要上程式碼了:

        $funcList = array();

	// 註冊函式
	$funcList['begin'] = function(){
		echo 'For loop begins! ...<br/>';
	};

	$funcList['endNormal'] = function(){
		echo 'For loop ends successfully! ...<br/>';
	};

	$funcList['error'] = function(){
		echo 'An error occured, For loop ends ...<br/>';
	};

	for($i=0; $i<10; ++$i){
		if($i == 0 && array_key_exists('begin', $funcList)){
			handleEvent($funcList['begin']);
		}
		if(($rand = rand(0,9)) == 9 && array_key_exists('error', $funcList)){
			handleEvent($funcList['error']);
			break;
		}
		if($i == 9 && array_key_exists('endNormal', $funcList)){
			handleEvent($funcList['endNormal']);
		}
	}

	function handleEvent($callback){
		echo 'An event occured! ...<br/>';
		if(is_callable($callback)) $callback();
	}


好像有點兒意思了:事先註冊了幾個處理不同“事件”的函式,然後,當“事件”發生時,“觸發”那些“事件處理函式”。

好吧,到此有那麼一點兒意思了。來看看ThinkPHP 中的 “鉤子”原始碼:

class Hook
 {
    //action hooks array  
    private static $actions = array();
    /**
     * ads a function to an action hook
     * @param $hook
     * @param $function
     */
    public static function add_action($hook,$function)
    {   
        $hook=mb_strtolower($hook,CHARSET);
        // create an array of function handlers if it doesn't already exist
        if(!self::exists_action($hook))
        {
            self::$actions[$hook] = array();
        }
        // append the current function to the list of function handlers
        if (is_callable($function))
        {
            self::$actions[$hook][] = $function;
            return TRUE;
        }
        return FALSE ;
    }
    /**
     * executes the functions for the given hook
     * @param string $hook
     * @param array $params
     * @return boolean true if a hook was setted
     */
    public static function do_action($hook,$params=NULL)
    {
        $hook=mb_strtolower($hook,CHARSET);
        if(isset(self::$actions[$hook]))
        {
            // call each function handler associated with this hook
            foreach(self::$actions[$hook] as $function)
            {
                if (is_array($params))
                {
                    call_user_func_array($function,$params);
                }
                else
                {
                    call_user_func($function);
                }
                //cant return anything since we are in a loop! dude!
            }
            return TRUE;
        }
        return FALSE;
    }
    /**
     * gets the functions for the given hook
     * @param string $hook
     * @return mixed
     */
    public static function get_action($hook)
    {
        $hook=mb_strtolower($hook,CHARSET);
        return (isset(self::$actions[$hook]))? self::$actions[$hook]:FALSE;
    }
    /**
     * check exists the functions for the given hook
     * @param string $hook
     * @return boolean
     */
    public static function exists_action($hook)
    {
        $hook=mb_strtolower($hook,CHARSET);
        return (isset(self::$actions[$hook]))? TRUE:FALSE;
    }
 }
 
    /**
     * Hooks Shortcuts not in class
     */
    function add_action($hook,$function)
    {
        return Hook::add_action($hook,$function);
    }
 
    function do_action($hook)
    {
        return Hook::do_action($hook);
    }

使用它:

//新增鉤子
 Hook::add_action('unique_name_hook','some_class::hook_test');
 //或使用快捷函式新增鉤子:
add_action('unique_name_hook','other_class::hello');
add_action('unique_name_hook','some_public_function');
 //執行鉤子
do_action('unique_name_hook');//也可以使用 Hook::do_action();

來分析下這個 Hook 類:

1:首先,它是個單例類,(只允許有一個類的例項化)。在提供了“註冊”和“觸發”兩個方法。

2:所有“註冊”的“事件處理函式”,被儲存在物件的成員屬性 $actions 中,並且,允許為 “同一個事件”“註冊”“多個不同的事件處理函式”。

3:這些“事件處理函式”,可以是某個類的某個成員方法。

其實,看到這裡,可以發現,這和 javascript 很像,javascript 允許自定義事件,也允許為同一事件繫結多個事件處理函式。而且,javascript 還提供了對“事件冒泡”的解決。

總結一下:

1:鉤子的實現首先基於:通過變數呼叫函式。

2:要明白函式作為引數傳遞,即回撥函式,的使用。

3:ThinkPHP 的 Hook 類,涉及到一些 “類的自動載入” 和 “使用者自定義函式呼叫”。

相關推薦

鉤子系統原理ThinkPHP 鉤子分析

鉤子系統,乍一看,好高大上,讓人摸不到頭腦。其實,大多技術或者方案,它總要起個名字,要是瞭解了其原理,這個名字其實也不必糾結。以下都是個人觀點: 首先,我們來一段php程式碼: <?php function deleteData(){ echo 'Delet

ReentrantLock實現原理源碼分析

獲取 累加 還在 set 共享變量 font except 區別 bool   ReentrantLock是Java並發包中提供的一個可重入的互斥鎖。ReentrantLock和synchronized在基本用法,行為語義上都是類似的,同樣都具有可重入性。只不過相比原生的S

1.Java集合-HashMap實現原理源碼分析

int -1 詳細 鏈接 理解 dac hash函數 順序存儲結構 對象儲存   哈希表(Hash Table)也叫散列表,是一種非常重要的數據結構,應用場景及其豐富,許多緩存技術(比如memcached)的核心其實就是在內存中維護一張大的哈希表,而HashMap的實

NFS網絡文件系統原理案例

NFS 菜鳥 從現在開始我決定把我所學的知識以博客的形式分享給大家,希望對和我一樣的菜鳥,同時夢想成為一只老鳥的IT小夥伴有一定的幫助!而對於我而言,這本身也是一種學習呢!好了廢話不多說,我們開始進入主題;我們人在接觸一個新事物或者是一個新技一個新技術的時候,我們往往想到的第一個問題就是“這是什麽呀?

HashMap實現原理源碼分析

響應 應用場景 取模運算 圖片 mat 直接 maximum 計算 時間復雜度 哈希表(hash table)也叫散列表,是一種非常重要的數據結構,應用場景及其豐富,許多緩存技術(比如memcached)的核心其實就是在內存中維護一張大的哈希表,而HashMap的實現原理也

【讀書筆記】Cronjob原理源碼分析

之前 jobs 所有 res net pes 垃圾回收gc ive 發現 原文鏈接:https://mp.weixin.qq.com/s?__biz=MzI0NjI4MDg5MQ==&mid=2715291842&idx=1&sn=e605f9b40

一文簡單理解“推薦系統原理架構

本文主要介紹什麼是推薦系統,為什麼需要推薦系統,如何實現推薦系統的方案,包括實現推薦系統的一些常見模型,希望給讀者提供學習實踐參考。 為什麼需要推薦系統                      

瀏覽器渲染原理web前端分析,從瀏覽器渲染原理談頁面優化

瀏覽器渲染原理及web前端分析 瀏覽器的主要功能 使用者介面:包括位址列、後退/前進按鈕、書籤目錄等,也就是除了用來顯示你所請求頁面的主視窗之外的其他部分。 瀏覽器引擎:用來查詢及操作渲染引擎的介面。另外還用來操作瀏覽器的資料儲存。 渲染引擎:用來顯示請求的內容,例如,如果請求內容為html

編譯原理實踐-----詞法分析

詞法分析 【實驗目的】 通過設計編制除錯一個具體的詞法分析程式,加深對詞法分析原理的理解。並掌握在對程式設計語言源程式進行掃描過程中將其分解為各類單詞的詞法分析方法。掌握對字元進行靈活處理的方法。 程式開始變得複雜起來,可能是大家目前編過的程式中最複雜

資料庫系統原理應用教程複習筆記(第3 版)

最近在複習資料庫相關知識點,過幾天就要考試了; 第一章 資料庫基礎知識 1、資料庫管理是資料處理的基礎工作,資料庫是資料管理的技術和手段。資料庫中的資料具有整體性和共享性。 1.2、資料庫系統的核心:資料庫管理系統。 1.3、資料庫核心:資料模型; 2、資料庫(DB)是一個按資料結構來儲存和管理資料的

Android中三級快取實現原理LruCache 原始碼分析

介紹 oom異常:大圖片導致 圖片的三級快取:記憶體、磁碟、網路 下面通過一張圖來了解下三級快取原理: 程式碼: public class Davince { //使用固定執行緒池優化 private static Exec

DNS欺騙原理工作工程分析

DNS欺騙   DNS欺騙是這樣一種中間人攻擊形式,它是攻擊者冒充域名伺服器的一種欺騙行為,它主要用於向主機提供錯誤DNS資訊,當用戶嘗試瀏覽網頁,例如IP地址為XXX.XX.XX.XX ,網址為www.bankofamerica.com,而實際上登入的確實IP地址YY

[Android系統原理開發要點詳解

第1章 Android系統概述 1 1.1 基礎知識 1 1.1.1 Android開發系統的由來 1 1.1.2 行動電話系統開發模式 2 1.1.3 未來行動電話的功能及Android的優勢 4 1.2 Android的開發工作 6 1.2.1 Android移植

嵌入式系統原理應用教程期末複習

嵌入式系統原理期末複習 第一章 嵌入式系統概述 1.嵌入式系統的特點。 嵌入性、專用性、計算機系統。 1.系統核心小。2.專用性強。3.執行環境差異大。4.可靠性要求高。5.系統精簡和高實時性作業系統。6.具有固化在非易失性儲存器中的程式碼。7.嵌入式系統開發工作和環境。

Mina工作原理業務流程分析

Mina是Apache社群維護的一個開源的高效能IO框架, 在業界內久經考驗, 廣為使用. Mina與後來興起的高效能IO新貴Netty一樣, 都是韓國人Trustin Lee 的大作, 二者的設計理念是極為相似. 在作為一個強大的開發工具的同時, 這兩個

HashMap實現原理源碼分析(jdk1.8)

for 離散 兩種 收集器 sta 循環 false lar rem HashMap底層由數組+鏈表+紅黑樹組成,可接受null值,非線程安全 1、基本屬性 transient Node<K,V>[] table; //hashmap

Salesforce學習之路-developer篇(五)一文讀懂Aura原理實戰案例分析

很喜歡曾經看到的一句話:以輸出倒逼輸入。以輸出的形式強制自己學習,確實是高效的學習方式,真的很棒。以下僅為個人學習理解,如有錯誤,歡迎指出,共同學習。   1. 什麼是Lightning Component框架?  Lightning Component框架是一個UI框架,用於為移動和

java動態代理基本原理proxy原始碼分析

本系列文章主要是博主在學習spring aop的過程中瞭解到其使用了java動態代理,本著究根問底的態度,於是對java動態代理的本質原理做了一些研究,於是便有了這個系列的文章 為了儘快進入正題,這裡先跳過spring aop和java動態代理的使用流程的講解,這部分內容後面再單獨寫文章整理   不

Flask框架鉤子函式使用方式應用場景分析

Flask框架鉤子函式使用方式及應用場景分析 在正常執行的程式碼前中後,強行插入執行一段你想要實現的功能的程式碼,這種函式就叫做鉤子函式。鉤子函式就是等同於高速公路上的收費站,進高速之前給你一個卡,並檢查你是否超重。離開之前收你,也可以攔住你安檢一下。 一. 基礎概念:

SSO單點登入系統原理分析功能實現

Sso系統分析什麼是sso系統SSO英文全稱Single Sign On,單點登入。SSO是在多個應用系統中,使用者只需要登入一次就可以訪問所有相互信任的應用系統。它包括可以將這次主要的登入對映到其他應用中用於同一個使用者的登入的機制。它是目前比較流行的企業業務整合的解決方案