当前位置:网站首页>TP5 automatic registration hook mechanism hook extension, with a complete case
TP5 automatic registration hook mechanism hook extension, with a complete case
2022-07-04 01:20:00 【Programmer base camp】
There are two ways to use hook mechanism , notes : You can only choose one of them :
1、 use thinkphp5 Built in hook call scheme . Configuration parameters jntoo_hook_call by true It works only when , For compatibility, the use of hook mechanism has been written
2、 Adopt its own hook calling scheme , This method supports hook classification , Hook weight automatic sorting
Personal not recommended think Built in hook as an extension of the system .
How to write auto load file :
Create a new one under the module hook Catalog , And create... In the directory Category.php file , Here's the picture :

The class name is equal to the hook type , Method name equals hook name .( notes : Types only exist in hook mechanism methods 2. Method 1 Only method name takes effect )
As shown in the figure :

We created Category Type of hook
There are two ways :
index and index_5
Method 1 Call method of :\think\Hook::listen('index'); You can directly call Category class index Method .
Output results :

Method 2 Call method of :\app\common\Hook::call('Category','index'); You can call Category class index Methods and index_5 Method
Output results :

Method 2 Why can call Category.index Hook will call Category.index_5 This hook ? We will explain this later .
Tell me a little story
One day, the customer said that he wanted to implement a member registration module .
I've finished the registration module of code members after typing for half a day .
The next day the customer said “ Now there is no problem with customer registration , I wonder if I can add it to him after registration 50 integral , So that he can make some consumption .”, I said, “ That's all right. ”
After knocking on the code for half a day, I completed the customer's requirements . Now after registering for membership , Free 50 I've got points .
On the third day, my colleague asked me if you did not get a registration module and give points in the system two days ago ? I said yes . Colleagues said “ Submit this to you svn library , I also have a customer who wants to get a registration module and give away points , Also add send mail verification ”, I :“ well , But you should add email verification yourself .” Code commit to svn library ,
My colleague knocked the code for a long time , Finished sending email .
On the fourth day, I asked my colleague to submit SVN library , Let me synchronize the code .
On the fifth day, another customer asked me “ Does your registration module have a member registration verification mobile phone ”, Of course, I can only say that there is ( In fact, there is no SMS authentication ), Customer said ” Can you set up the environment for me to test ?“, I can only say :“ Sorry, sir , We haven't installed the environment yet , I'll fix this for you tomorrow , You are testing ”, Customer said “ good ”
It took a long time to add the member registration mobile phone verification to the member registration module .
On the sixth day, the customer thought it was very good .
Here's the story .
Suppose the formation of the above member registration module is such a code fragment :
namespace app\index\controller;class member{function register($username , $password , $tel , $email){// The code added on the fifth day :if( Whether SMS verification )VerifTel($tel , Verification Code );// Code written on day one :if(table('member')->where('username' , $username)->count()){$this->error = ' User name already exists 'return false;}$uid = Write to the database to get new users UID.... Omit most of the code// The code added the next day :if( Bonus points )sendPoints($uid . Bonus points ); // Send points 50// On the third dayif( Send E-mail )sendEmail($uid , mail );return true;}}
As we can see from the above , When you finish writing a function module , I don't know the situation of some customers' needs , We will add code to the current module .
If you keep on adding , When you look back at the code, you will find that you have too much code .
Can this code become more elegant
What if we add a hook mechanism to this code ?
Look at the code below
namespace app\index\controller;class member{function register($username , $password , $tel , $email){// I don't know what it will be like in the future , First add a front hook , Parameters :$username,$password,$tel,$email$param = [ $username,$password,$tel,$email ];\app\common\Hook::call('member','registerPre',$param);// Code written on day one :if(table('member')->where('username' , $username)->count()){$this->error = ' User name already exists 'return false;}$uid = Write to the database to get new users UID.... Omit most of the code// I don't know what it will be like in the future , Add a hook after successful registration , Parameters $uid$param = [ $uid ];\app\common\Hook::call('member','registerSuccess',$param);return true;}}
So the problem is how to solve the hook problem ?
Suppose our classes have been registered in the hook :
Let's finish the next day , The following code :
namespace app\index\hook;class member{// Hook type , Hang the member Type hook , Medium registerSuccess hookfunction registerSuccess($uid){if( Bonus points )sendPoints($uid . Bonus points ); // Send points 50}}
What should my colleagues do with my code on the third day ? Then I will tell him :“ I have put two hooks here , One is to register the front hook , One is the hook after successful registration ” And tell him the type of hook , name , There are also corresponding parameters , Colleagues' code will become like this
namespace app\tongshi\hook;class member{// Hook type , Hang the member Type hook , Medium registerSuccess hookfunction registerSuccess($uid){if( Send E-mail )sendEmail($uid , mail );}}
On the fifth day, it was like this :
namespace app\index\hook;class member{// Hang the member Type hook , Medium registerSuccess hookfunction registerSuccess($uid){if( Bonus points )sendPoints($uid . Bonus points ); // Send points 50}// Hang the member Type hook registerPre hookfunction registerPre(){if( Whether SMS verification )VerifTel($tel , Verification Code );}}
Back to what we said above “ Why can call Category.index Hook will call Category.index_5 This hook ?”
When designing the hook mechanism, I think that hooks may have a sequence , And designed a number that can write weight sorting , Add a number at the end , Sort from small to large , The actual hook registration will automatically delete the tail “_ Numbers ”:
One : Let's talk about the hook mechanism first
In the project code , You think we need to expand ( Don't expand for the time being ) Place a hook function in place of , When you need to expand , Attach the classes and functions to this hook , You can expand .
That's the idea. It sounds general .
When redeveloping the code written by others , If there is a hook mechanism , The author will tell you where to hook , When you expand, you can upgrade and expand without changing the original code .
This plug-in extends the configuration parameter information :
1、jntoo_hook_cacheBoolean value , Whether to enable hook compilation cache , You only need to compile once after opening , In the future, it will become lazy loading , If a new hook is installed , You need to call Hook::clearCache() Clear cache2、jntoo_hook_callBoolean value , Whether to use think Hook system . If the value is true, use think After the hook , You will not be able to use weight sorting and hook automatic classification , Only the methods in the class will be automatically registered to think Hook mechanism3、jntoo_hook_pathUnder a folder PHP Files automatically register hooks for themConfiguration to realizejntoo_hook_path => [['path'=>' Your path ', // A slash must be added at the end of the path "/"'pattern'=> ' The rules , Class matching rules ' for example :'/plugin\\\\module\\\\hook\\\\([0-9a-zA-Z_]+)/'],....]4、jntoo_hook_pluginAutomatic compilation of multi module directories , Add hook Catalog , Under this directory php The file will automatically register the hookConfiguration to realize :'jntoo_hook_plugin' => [['path'=>' Yours app The module path ','pattern'=> ' The rules , Class matching rules ' for example :'/plugin\\\\([0-9a-zA-Z_]+)\\\\hook\\\\([0-9a-zA-Z_]+)/'],....]
Please be there. application/tags.php
'app_init' Add :'\\app\\common\\Hook'
for example :
// Application behavior extension definition file
return [
// Application initialization
'app_init' => [
'\\app\\common\\Hook'
],
// App start
'app_begin' => [],
// Module initialization
'module_init' => [],
// The operation begins
'action_begin' => [],
// View content filtering
'view_filter' => [],
// Log write
'log_write' => [],
// End of application
'app_end' => [],
];
Please create your own file :
application\index\controller\Index.php Hook file
namespace app\index\controller;use app\common\Hook;use think\Hook AS thinkHook;class Index{public function index(){Hook::call('Category' , 'index');}}
application\index\hook\Category.php Hook file
<?php/*** Created by PhpStorm.* User: JnToo* Date: 2016/11/12* Time: 1:11*/namespace app\index\hook;class Category{function index(){echo ' I am a Category Type hook index Method <br>';}function index_5(){echo ' I am a Category Type hook index Method , My weight is relatively low <br>';}}
application\common\hook.php Master file
<?php/*** Created by PhpStorm.* User: JnToo* Date: 2016/11/11* Time: 22:57*/namespace app\common;use think\Config;use think\Hook as thinkHook;use think\Cache;/*** Please be there. application/tags.php* 'app_init' Add :'\\app\\common\\Hook'* for example :* // Application behavior extension definition filereturn [// Application initialization'app_init' => ['\\app\\common\\Hook'],// App start'app_begin' => [],// Module initialization'module_init' => [],// The operation begins'action_begin' => [],// View content filtering'view_filter' => [],// Log write'log_write' => [],// End of application'app_end' => [],];* Class Hook* @package app\common*/class Hook{/*** Use counters when compiling hooks* @var int*/static protected $index = 0;/*** Add reference count* @var int*/static protected $indexAdd = 1;/*** Compiled hook list* @var array*/static protected $hookList = array();/*** application/config.php Add the following configuration information to the file* @var array*/static protected $default =[// Whether to enable hook compilation cache , You only need to compile once after opening , In the future, it will become lazy loading , If a new hook is installed , You need to call Hook::clearCache() Clear cache'jntoo_hook_cache'=>false,// Whether the hook is used think Hook system'jntoo_hook_call'=>false ,/*** Under a folder hook load , Configuration file method implementation* jntoo_hook_path => [* [* 'path'=>' Your path ', // A slash must be added at the end of the path "/"* 'pattern'=> ' The rules , Class matching rules ' for example :'/plugin\\\\module\\\\hook\\\\([0-9a-zA-Z_]+)/'* ],* ....* ]*/'jntoo_hook_plugin'=>[],/*** Automatic search under multi module directory , Configuration file method implementation* 'jntoo_hook_plugin' => [* [,* 'path'=>' Yours app The module path '* 'pattern'=> ' The rules , Class matching rules ' for example :'/plugin\\\\([0-9a-zA-Z_]+)\\\\hook\\\\([0-9a-zA-Z_]+)/'* ],* ....* ]*/'jntoo_hook_plugin'=>[],];/*** Provide behavior calls*/public function run(){self::init();}/*** Register hook* @param $type Hook type* @param $name Hook name* @param $param \Closure|array*/static public function add($type , $name , $param , $listorder = 1){$key = strtolower($type .'_'.$name);isset(self::$hookList[$key]) or self::$hookList[$key] = [];self::$hookList[$key][$listorder.'_'.self::$indexAdd++] = $param;ksort(self::$hookList[$key]);// compatibleif(Config::get('jntoo_hook_call')){thinkHook::add($name , $param);}return;}/*** Clear the cache of the compilation hook*/static public function clearCache(){// Compile hook cache clearlyif(Config::get('jntoo_hook_cache')){cache('jntoo_hook_cache' , null);}}/*** Carry out the hook* @param $type string* @param $name string* @param array $array* @param mixe*/static public function call($type , $name , &$array = array()){static $_cls = array();$ret = '';if(Config::get('jntoo_hook_call')){return thinkHook::listen($name , $array);}else{$key = strtolower($type.'_'.$name);// Own call schemeif(isset(self::$hookList[$key])){foreach(self::$hookList[$key] as $r){// Closure processing$result = '';if(is_callable($r)){$result = call_user_func_array($r, $array);}elseif(is_object($r)){// Define your own object hookif(method_exists($r , $name)){$result = call_user_func_array(array($r , $name), $array);}}else{// Automatically searched hooks$class = $r['class'];if(class_exists($class , false)){// If it doesn't existif($r['filename'])require_once(ROOT_PATH.$r['filename']);}if(class_exists($class , false)){if(!isset($_cls[$class])){$_cls[$class] = new $class();}$func = $r['func'];$result = call_user_func_array(array($_cls[$class] , $func), $array);}}if($result)$ret.=$result;}}}return $ret;}/*** Initialization hook*/static protected function init(){// Get the cache of the hookself::$hookList = self::getCache();if(!self::$hookList){// Save in the current variable$saveArray = [];// The hook does not exist , First search app Module under directory//echo APP_PATH;//echo ROOT_PATH;$result = self::searchDir(APP_PATH);// Compile this module firstself::compileHook($result , '/app\\\\([0-9a-zA-Z_]+)\\\\hook\\\\([0-9a-zA-Z_]+)/' , $saveArray);//print_r($saveArray);// Multiple modules realize search loading$jntooHook = Config::get('jntoo_hook_plugin');if($jntooHook){foreach($jntooHook as $t){$result = self::searchDir($t['path']);self::compileHook($result , $t['pattern'] , $saveArray);}}// Single path module search$jntooHook = Config::get('jntoo_hook_path');if($jntooHook){foreach($jntooHook as $t){$result = [];self::searchHook($t['path'] , $result);self::compileHook($result , $saveArray);}}// Compile the complete , Now let's do a weight sortforeach($saveArray as $k=>$t){ksort($saveArray[$k]);}self::setCache($saveArray);self::$hookList = $saveArray;}//print_r(self::$hookList);$calltype = Config::get('jntoo_hook_call');// Detect his calling method , Need to register to think in , It is not recommended to register to think in ,// Because this system contains the form of classification , After you register, you will not be able to use the sorting functionif($calltype){// Sign up for think In the hookself::registorThink();}else{// Register system behavior hookself::registorCall();}}/*** Register system behavior calls*/static protected function registorCall(){thinkHook::add('app_init' , function( &$params = null ){$arg = [&$params];Hook::call('system' , 'app_init' , $arg);});thinkHook::add('app_begin' , function( &$params = null ){$arg = [&$params];Hook::call('system' , 'app_begin' , $arg);});thinkHook::add('module_init' , function( &$params = null ){$arg = [&$params];Hook::call('system' , 'module_init' , $arg);});thinkHook::add('action_begin' , function( &$params = null ){$arg = [&$params];Hook::call('system' , 'action_begin' , $arg);});thinkHook::add('view_filter' , function( &$params = null ){$arg = [&$params];Hook::call('system' , 'view_filter' , $arg);});thinkHook::add('app_end' , function( &$params = null ){$arg = [&$params];Hook::call('system' , 'app_end' , $arg);});thinkHook::add('log_write' , function( &$params = null ){$arg = [&$params];Hook::call('system' , 'log_write' , $arg);});thinkHook::add('response_end' , function( &$params = null ){$arg = [&$params];Hook::call('system' , 'response_end' , $arg);});}/*** Register the hook in thinkHook In the hook*/static protected function registorThink(){foreach(self::$hookList as $key=>$list){foreach($list as $r){thinkHook::add($r['func'] , $r['class']);}}}/*** Search the hook file in the directory* @param $path string* @param $saveArray array Saved file path* @return null*/static protected function searchHook( $path , &$saveArray){$fp = opendir($path);if($fp){while($file = readdir($fp)){if(substr($file , -4) == '.php'){$saveArray[] = $path.$file;}}}}/*** Compile hook , After compilation, it is directly saved in static member variables self::$hookList* @param $filelist array File path* @param $namespace string Namespace rules* @param $saveHook array preservation Hook* @return null*/static protected function compileHook($filelist , $namespace , &$saveHook){$root_path = strtr(ROOT_PATH,'\\' , '/');//print_r($filelist);// Current reference count$index = self::$index;$indexAdd = self::$indexAdd;foreach ($filelist as $file){require_once($file);// Get the loaded class$class_list = get_declared_classes();// Search countersfor($len = count($class_list);$index<$len;$index++){$classname = $class_list[$index];if(preg_match($namespace , $classname)){// This class meets our needs$ec = new \ReflectionClass($classname);// The type of hook$type = basename(strtr($classname , '\\' , '/'));foreach($ec->getMethods() as $r){if($r->name[0] != '_' && $r->class == $classname){// I don't know how to realize sorting yet The method name is followed by$name = $r->name;$listorder = 1;if(strpos($name , '_') !== false){// There is a sort$temp = explode('_',$name);$num = array_pop($temp);if(is_numeric($num)){$name = implode('_' , $temp);$listorder = $num;}}$typename = strtolower($type.'_'.$name);!isset($saveHook[$typename]) AND $saveHook[$typename] = [];$saveHook[$typename][$listorder.'_'.$indexAdd++] = ['filename'=>str_replace($root_path,'',$file), // The advantage of saving the file path is convenient and fast loading , No need to search the path'class'=>$classname, // Save the name of the class'func'=>$r->name, // Save method name'listorder'=>$listorder // Sort , After compilation , Sort the weights];}}}}}self::$index = $index;self::$indexAdd = $indexAdd;}/*** @param $path Search module path* @return array*/static protected function searchDir( $path ){// Automatic directory completion$path = strtr(realpath($path),'\\' , '/');$char = substr($path,-1);if( $char != '/' || $char != '\\' ){$path .= '/';}$path .= '*';$dirs = glob($path, GLOB_ONLYDIR );$result = array();foreach($dirs as $dir){if(is_dir($dir .'/hook')){self::searchHook($dir .'/hook/' , $result);}}return $result;}/*** Get the compiled hook* @return bool|array*/static protected function getCache(){if(Config::get('jntoo_hook_cache')){// Access to the cachereturn cache('jntoo_hook_cache');}return false;}/*** Save the compiled cache* @param $value array* @return bool*/static protected function setCache( $value ){// Set to permanent cacheif(Config::get('jntoo_hook_cache')){cache('jntoo_hook_cache' , $value , null);}return true;}}
边栏推荐
- Release and visualization of related data
- GUI application: socket network chat room
- PMP 考试常见工具与技术点总结
- Mongodb learning notes: command line tools
- Mobile asynchronous sending SMS verification code solution -efficiency+redis
- 功能:将主函数中输入的字符串反序存放。例如:输入字符串“abcdefg”,则应输出“gfedcba”。
- The FISCO bcos console calls the contract and reports an error does not exist
- In the process of seeking human intelligent AI, meta bet on self supervised learning
- 7.1 learning content
- Sequence list and linked list
猜你喜欢

【.NET+MQTT】. Net6 environment to achieve mqtt communication, as well as bilateral message subscription and publishing code demonstration of server and client

AI 助力艺术设计抄袭检索新突破!刘芳教授团队论文被多媒体顶级会议ACM MM录用

51 MCU external interrupt

Function: find the sum of the elements on the main and sub diagonal of the matrix with 5 rows and 5 columns. Note that the elements where the two diagonals intersect are added only once. For example,

CLP information - how does the digital transformation of credit business change from star to finger?

Thinkphp6 integrated JWT method and detailed explanation of generation, removal and destruction

我管你什么okr还是kpi,PPT轻松交给你

Infiltration learning diary day19

Make drop-down menu

机器学习基础:用 Lasso 做特征选择
随机推荐
[dynamic programming] leetcode 53: maximum subarray sum
Install the pit that the electron has stepped on
1-Redis架构设计到使用场景-四种部署运行模式(上)
It's OK to have hands-on 8 - project construction details 3-jenkins' parametric construction
Meta metauniverse female safety problems occur frequently, how to solve the relevant problems in the metauniverse?
Stringutils and collectionutils
Avoid playing with super high conversion rate in material minefields
Introduction to unity shader essentials reading notes Chapter III unity shader Foundation
OS interrupt mechanism and interrupt handler
[prefix and notes] prefix and introduction and use
Future source code view -juc series
Introduction to A-frame virtual reality development
关于 uintptr_t和intptr_t 类型
Hash table, string hash (special KMP)
不得不会的Oracle数据库知识点(一)
It's OK to have hands-on 8 - project construction details 3-jenkins' parametric construction
Wechat official account and synchronization assistant
Day05 table
51 single chip microcomputer timer 2 is used as serial port
Employees' turnover intention is under the control of the company. After the dispute, the monitoring system developer quietly removed the relevant services