川山甲

追求内心的非常平静!瞬间清空所有的杂念,达到物我两忘!

  博客园  :: 首页  ::  :: 联系 :: 订阅 订阅  :: 管理
  105 随笔 :: 0 文章 :: 1591 评论 :: 82万 阅读
 
  
  作为程序员,设计出优雅而完美的系统,永远是让我们非常兴奋的事情。高手不在于你会多少语言,而在于你有多高的思想。
 
  在设计中,怎么体现自身价值,那就是要比别人多想几步。
 
  讲钩子程序,起源是对用户提交的参数校验(永远不要相信用户),一开始为了赶工期,按照比较传统的方式,每个接口里重复性的对参数进行过滤。后面随着业务的发展(功能迭代),系统的维护成本越来越高,遂想一个更高级的方式进行处理。借鉴同事之前的代码,使用钩子方式进行重构。
 
  之前写过javascript 钩子机制, 偏后钩,可以互相借鉴下。
 
脉路
  
 
 
 
概念
  
  把一段程序块(执行体)通过某种方式挂入系统中,从而获得对系统的控制权。
 
       注意下图挂钩位置:
 

 

 
 
应用
  
  小的方面: 进行基础的入参校验或消息过滤。
  大的方面:组件化,可在系统中进行插拔管理。
  
  优点:
    1、降低系统的耦合度;
    2、降低开发、测试人力成本,用少量的代码实现高可用功能;
    3、提高模块间的可用性;
    4、通过配置(配置文件or数据库)的方式升级接口。
  缺点:
    学习成本过高;
    系统复杂度提升;
 

 
实现思想
  
 
     配置文件的方式进行钩子定义、钩子链管理(使用“组”的概念)、挂钩。
 
  

 

    钩子:程序执行体;
      钩子组: 钩子链的分类定义;
           挂钩: 入口(MVC中action或者controller)与钩子组进行绑定。
 
 

 
实现方式
  
   
 
  
       挂钩器(继承类):
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
137
138
139
<?php
/**
 * @name Service_Page_Test
 * @desc page层对接第三方抽象类
 * @author 
 */
abstract class Service_Page_Test
{
    public $hookGroupPrev = null; // 前钩子组
    public $hookGroupAfter = null; // 后钩子组
    public $hookReturn = array(); //钩子返回值
    public $reqData = null; // page模块分析的数据
 
    /**
     * 获取需要验证的参数配置
     * @return array
     */
    public function _getCheckParams()
    {
        return array();
    }
 
 
 
    /**
     * 入口方法
     * @param array $arrInput
     * @return array
     */
    public function execute($arrInput)
    {
        $res = array(
            'errno' => Test_Errno::ERRNO_SUCCESS,
            'errmsg' => Test_Errno::$ERRMSG[Test_Errno::ERRNO_SUCCESS],
        );
        try {
            $this->_init($arrInput);
            $this->_beforeExecute();
            $res = $this->doExecute($arrInput);
            $this->_afterExecute();
        } catch (Test_Exception $e) {
            $res = array(
                'errno' => $e->getCode(),
                'errmsg' => $e->getMessage(),
            );
        } catch (Exception $e) {
            $res = array(
                'errno' => $e->getCode(),
                'errmsg' => $e->getMessage(),
            );
 
        }
        return $res;
    }
 
 
 
    /**
     * auto exec
     * @param array $arrInput
     * @throws Exception
     * @return array
     */
    protected function doExecute($arrInput){
    }
 
 
    /**
     * 获取权限信息
     * @param array $arrInput
     * @return array
     */
    public function _init($arrInput)
    {
        $pageModulesConf = Conf::getConf('page/' . get_class($this));
        $this->reqData = $arrInput;
        $this->hookGroupPrev[] = $pageModulesConf['hook_group']['prev'];
        $this->hookGroupAfter[] = $pageModulesConf['hook_group']['after'];
    }
 
 
    /**
     * 执行filter
     * @param string
     */
    public function _beforeExecute()
    {
        if (!empty($this->hookGroupPrev) && is_array($this->hookGroupPrev)) {
            foreach ($this->hookGroupPrev as $hookGroups) {
                foreach ($hookGroups as $hookGroup) {
                    $this->_executeHook($hookGroup, $this->reqData);
                }
            }
        }
    }
 
 
    /**
     * @param array $arrInput
     * @return array
     */
    public function _afterExecute()
    {
        if (!empty($this->hookGroupAfter) && is_array($this->hookGroupAfter)) {
            foreach ($this->hookGroupAfter as $hookGroups) {
                foreach ($hookGroups as $hookGroup) {
                    $this->_executeHook($hookGroup, $this->reqData);
                }
            }
        }
    }
 
 
    /**
     * 执行filter
     * @param string
     */
    public function _executeHook($hookGroup, $reqData)
    {
 
        $hookGroupConf = Conf::getConf('hook/group/' . $hookGroup);
        if(!empty($hookGroupConf)){
            foreach($hookGroupConf as $hook){
                $hookConf = Conf::getConf('hook/hook/' . $hook);
                $class = $hookConf['class'];
                $method = $hookConf['method'];
                $inputParams = isset($hookConf['getInputParams']) ? $this->{$hookConf['getInputParams']}() : null;
                if (class_exists($class)) {
                    $obj = new $class();
                    if (method_exists($obj, $method)) {
                        $this->hookReturn[$hook][] =  $obj->$method($inputParams, $reqData);
                    }
                }
            }
        }
 
    }
 
}

  

 

  hook.conf

复制代码
# 钩子组
[group] [.check_req_customer]
0 : checkReqCustomerBaseInfo [.after_demo] 0 : afterDemo # 钩子 [hook] [.checkReqCustomerBaseInfo] class: Service_Page_Hook_Customer method: checkBaseInfo getInputParams: _getCheckParams [.afterDemo] class: Service_Page_Hook_Customer method: afterDemo getInputParams: _getCheckParams
复制代码

 

  page.conf
1
2
3
4
5
6
7
[Service_Page_Input]
#绑定钩子组
[.hook_group]
[..prev]
0 : check_req_customer
[..after]
0 : after_demo

  

 
 
 
推荐
 
 
 
 
 
 
 
posted on   川山甲  阅读(3166)  评论(2编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示