之前對鉤子還是有點感興趣,寫下了之前的設計模式,順手看了鉤子,其實你可以比對看一下。


鉤子和我上一篇的觀察者模式或者策略模式很有關聯,應該就是相通的。


應用場景:來之TP行為的文字—》框架的執行流程中,例如路由檢測是一個行為,靜態快取是一個行為,使用者許可權檢測也是行為,大到業務邏輯,小到瀏覽器檢測、多語言檢測等等都可以當做是一個行為,甚至說你希望給你的網站使用者的第一次訪問彈出Hello,world!這些都可以看成是一種行為,行為的存在讓你無需改動框架和應用,而在外圍通過擴充套件或者配置來改變或者增加一些功能。

外加一幅圖:竟然需要用Flash來上傳圖片,可惜瀏覽器不支援,我也很討厭Flash。那麼就沒辦法來打字吧。鉤子程式對於我最大的體驗就是我第一次和老闆做一個簡單的手機編輯器,註冊繳費使用,所以每個頁面都要手動寫下固定的程式碼,驗證是否繳費。所以每個頁面雷打不動的幾行程式碼,如今覺得可以使用鉤子或者說鉤子應運而生。如果你也遇到這種情景,就可以考略,當然,寫了鉤子,也許你還需要每個地方寫一下,引用下,但是你對於驗證的程式實現的維護就很方便了。TP的行為更進一步,在整個框架的幾個關鍵點設定了標籤,之要繫結行為就可以。


幫你理解狗子的小程式如下:

1
2
3
4
5
6
7
8
9
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
49
50
<?php
    //統一對外的類
    class Hook{
        private $hooklist = null;
 
        //感覺這裡很像觀察者模式或者是策略模式
        public function add($action_hook){
            $this->hooklist[]=new $action_hook();
        }
        //觸發事件
        public function exec(){
            foreach($this->hooklist as $action_hook){
                $action_hook->act();//鉤子中統一的方法
            }
        }
    }
    //不同用途的鉤子具體物件,比如說驗證密碼,驗證許可權,統一加密等等,
    class action_hook_1{
        public function act(){
            echo "我來做第一件事";
        }
    }
    class action_hook_2{
        public function act(){
            echo "我來做第2件事";
        }
    }
    class action_hook_3{
        public function act(){
            echo "我來做第3件事";
        }
    }
//需要繫結鉤子的具體物件
class Ball{
    public function down(){
        echo `我需要做一些通用的驗證工作`;
        //註冊事件,這裡就可以載入相應的鉤子類,因為在一個檔案,直接使用
        $hook new Hook();
        $hook->add("action_hook_1");
        $hook->add("action_hook_2");
        $hook->add("action_hook_3");
        $hook->exec();
    }
    //淡然也可以註冊完就直接執行鉤子,也可以寫到單獨方法
    public function exec(){
    }
}
 
$ball new Ball();
$ball->down();

估計看完這個你應該可以理解八九不離十。不理解也沒關係,這並不影響你的程式書寫,過段時間 再看估計就懂了,不著急。


然後TP裡面的Hook類我也附錄在後面,方法都是通用的listen,add註冊,run執行,然後在相應的名稱空間寫下你的鉤子想要實現的具體程式碼。然後TP主要是利用配置檔案來進行說明各個檔案的關係,這個是很不錯,也是需要學習,也是很新手容易困惑的地方。(這件事我想當推薦看手冊,不用看雜七亂八的文章TP5.0的行為在擴充套件裡面)思路就是這樣了。


附錄:TP  hook類

1
2
3
4
5
6
7
8
9
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
 
namespace think;
 
class Hook
{
 
    private static $tags = [];
 
    /**
     * 動態新增行為擴充套件到某個標籤
     * @param string    $tag 標籤名稱
     * @param mixed     $behavior 行為名稱
     * @param bool      $first 是否放到開頭執行
     * @return void
     */
    public static function add($tag$behavior$first = false)
    {
        isset(self::$tags[$tag]) || self::$tags[$tag] = [];
        if (is_array($behavior) && !is_callable($behavior)) {
            if (!array_key_exists(`_overlay`$behavior) || !$behavior[`_overlay`]) {
                unset($behavior[`_overlay`]);
                self::$tags[$tag] = array_merge(self::$tags[$tag], $behavior);
            else {
                unset($behavior[`_overlay`]);
                self::$tags[$tag] = $behavior;
            }
        elseif ($first) {
            array_unshift(self::$tags[$tag], $behavior);
        else {
            self::$tags[$tag][] = $behavior;
        }
    }
 
    /**
     * 批量匯入外掛
     * @param array        $tags 外掛資訊
     * @param boolean     $recursive 是否遞迴合併
     */
    public static function import(array $tags$recursive = true)
    {
        if ($recursive) {
            foreach ($tags as $tag => $behavior) {
                self::add($tag$behavior);
            }
        else {
            self::$tags $tags + self::$tags;
        }
    }
 
    /**
     * 獲取外掛資訊
     * @param string $tag 外掛位置 留空獲取全部
     * @return array
     */
    public static function get($tag ``)
    {
        if (empty($tag)) {
            //獲取全部的外掛資訊
            return self::$tags;
        else {
            return array_key_exists($tag, self::$tags) ? self::$tags[$tag] : [];
        }
    }
 
    /**
     * 監聽標籤的行為
     * @param string $tag    標籤名稱
     * @param mixed  $params 傳入引數
     * @param mixed  $extra  額外引數
     * @param bool   $once   只獲取一個有效返回值
     * @return mixed
     */
    public static function listen($tag, &$params = null, $extra = null, $once = false)
    {
        $results = [];
        $tags    static::get($tag);
        foreach ($tags as $key => $name) {
            $results[$key] = self::exec($name$tag$params$extra);
            if (false === $results[$key]) {
                // 如果返回false 則中斷行為執行
                break;
            elseif (!is_null($results[$key]) && $once) {
                break;
            }
        }
        return $once end($results) : $results;
    }
 
    /**
     * 執行某個行為
     * @param mixed     $class 要執行的行為
     * @param string    $tag 方法名(標籤名)
     * @param Mixed     $params 傳人的引數
     * @param mixed     $extra 額外引數
     * @return mixed
     */
    public static function exec($class$tag ``, &$params = null, $extra = null)
    {
        App::$debug && Debug::remark(`behavior_start``time`);
        $method = Loader::parseName($tag, 1, false);
        if ($class instanceof Closure) {
            $result = call_user_func_array($class, [ & $params$extra]);
            $class  `Closure`;
        elseif (is_array($class)) {
            list($class$method) = $class;
 
            $result = (new $class())->$method($params$extra);
            $class  $class `->` $method;
        elseif (is_object($class)) {
            $result $class->$method($params$extra);
            $class  = get_class($class);
        elseif (strpos($class`::`)) {
            $result = call_user_func_array($class, [ & $params$extra]);
        else {
            $obj    new $class();
            $method = ($tag && is_callable([$obj$method])) ? $method `run`;
            $result $obj->$method($params$extra);
        }
        if (App::$debug) {
            Debug::remark(`behavior_end``time`);
            Log::record(`[ BEHAVIOR ] Run ` $class ` @` $tag ` [ RunTime:` . Debug::getRangeTime(`behavior_start``behavior_end`) . `s ]``info`);
        }
        return $result;
    }
 
}