序
作為程序員,設計出優雅而完美的系統,永遠是讓我們非常興奮的事情。高手不在于你會多少語言,而在于你有多高的思想。
在設計中,怎么體現自身價值,那就是要比別人多想幾步。
講鉤子程序,起源是對用戶提交的參數校驗(永遠不要相信用戶),一開始為了趕工期,按照比較傳統的方式,每個接口里重復性的對參數進行過濾。后面隨著業務的發展(功能迭代),系統的維護成本越來越高,遂想一個更高級的方式進行處理。借鑒同事之前的代碼,使用鉤子方式進行重構。
之前寫過javascript 鉤子機制, 偏后鉤,可以互相借鑒下。
脈路

概念
把一段程序塊(執行體)通過某種方式掛入系統中,從而獲得對系統的控制權。
注意下圖掛鉤位置:
應用
小的方面: 進行基礎的入參校驗或消息過濾。
大的方面:組件化,可在系統中進行插拔管理。
優點:
1、降低系統的耦合度;
2、降低開發、測試人力成本,用少量的代碼實現高可用功能;
3、提高模塊間的可用性;
4、通過配置(配置文件or數據庫)的方式升級接口。
缺點:
學習成本過高;
系統復雜度提升;
實現思想
配置文件的方式進行鉤子定義、鉤子鏈管理(使用“組”的概念)、掛鉤。
鉤子:程序執行體;
鉤子組: 鉤子鏈的分類定義;
掛鉤: 入口(MVC中action或者controller)與鉤子組進行綁定。
實現方式
掛鉤器(繼承類):
<?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
[Service_Page_Input] #綁定鉤子組 [.hook_group] [..prev] 0 : check_req_customer [..after] 0 : after_demo
推薦

喜歡編程
浙公網安備 33010602011771號