序
作为程序员,设计出优雅而完美的系统,永远是让我们非常兴奋的事情。高手不在于你会多少语言,而在于你有多高的思想。
在设计中,怎么体现自身价值,那就是要比别人多想几步。
讲钩子程序,起源是对用户提交的参数校验(永远不要相信用户),一开始为了赶工期,按照比较传统的方式,每个接口里重复性的对参数进行过滤。后面随着业务的发展(功能迭代),系统的维护成本越来越高,遂想一个更高级的方式进行处理。借鉴同事之前的代码,使用钩子方式进行重构。
之前写过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 |
推荐

喜欢编程
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架