当前位置:网站首页>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;}}
边栏推荐
- Introduction to A-frame virtual reality development
- All in one 1407: stupid monkey
- Characteristics of ginger
- Which insurance products can the elderly buy?
- 8. Go implementation of string conversion integer (ATOI) and leetcode
- Avoid playing with super high conversion rate in material minefields
- Mongodb learning notes: command line tools
- 查询效率提升10倍!3种优化方案,帮你解决MySQL深分页问题
- Query efficiency increased by 10 times! Three optimization schemes to help you solve the deep paging problem of MySQL
- gslb(global server load balance)技术的一点理解
猜你喜欢

Cloud dial test helps Weidong cloud education to comprehensively improve the global user experience

be based on. NETCORE development blog project starblog - (14) realize theme switching function

On covariance of array and wildcard of generic type

Luogu p1309 Swiss wheel
![[prefix and notes] prefix and introduction and use](/img/a6/a75e287ac481559d8f733e6ca3e59c.jpg)
[prefix and notes] prefix and introduction and use

Hbuilder link Xiaoyao simulator

Long article review: entropy, free energy, symmetry and dynamics in the brain

手机异步发送短信验证码解决方案-Celery+redis
![Cesiumjs 2022^ source code interpretation [8] - resource encapsulation and multithreading](/img/d2/99932660298b4a4cddd7e5e69faca1.png)
Cesiumjs 2022^ source code interpretation [8] - resource encapsulation and multithreading

Hash table, string hash (special KMP)
随机推荐
8. Go implementation of string conversion integer (ATOI) and leetcode
【.NET+MQTT】.NET6 环境下实现MQTT通信,以及服务端、客户端的双边消息订阅与发布的代码演示
51 MCU external interrupt
About uintptr_ T and IntPtr_ T type
Summary of common tools and technical points of PMP examination
Technical practice online fault analysis and solutions (Part 1)
不得不会的Oracle数据库知识点(四)
A dichotomy of Valentine's Day
不得不会的Oracle数据库知识点(一)
Which insurance products can the elderly buy?
C library function int fprintf (file *stream, const char *format,...) Send formatted output to stream
Luogu p1309 Swiss wheel
Infiltration learning diary day19
GUI 应用:socket 网络聊天室
C import Xls data method summary V (complete code)
Logical operator, displacement operator
Introduction to A-frame virtual reality development
MySQL deadly serial question 2 -- are you familiar with MySQL index?
Long article review: entropy, free energy, symmetry and dynamics in the brain
功能:将主函数中输入的字符串反序存放。例如:输入字符串“abcdefg”,则应输出“gfedcba”。