当前位置:网站首页>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;}}
边栏推荐
- Oracle database knowledge points that cannot be learned (III)
- Summary of common tools and technical points of PMP examination
- Design of database table foreign key
- What is the GPM scheduler for go?
- MySQL introduction - functions (various function statistics, exercises, details, tables)
- Technical practice online fault analysis and solutions (Part 1)
- “疫”起坚守 保障数据中台服务“不打烊”
- 长文综述:大脑中的熵、自由能、对称性和动力学
- Future source code view -juc series
- Summary of common tools and technical points of PMP examination
猜你喜欢

“疫”起坚守 保障数据中台服务“不打烊”

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

Query efficiency increased by 10 times! Three optimization schemes to help you solve the deep paging problem of MySQL

基于.NetCore开发博客项目 StarBlog - (14) 实现主题切换功能

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

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

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,

Huawei BFD and NQA
![CesiumJS 2022^ 源码解读[8] - 资源封装与多线程](/img/d2/99932660298b4a4cddd7e5e69faca1.png)
CesiumJS 2022^ 源码解读[8] - 资源封装与多线程

Avoid playing with super high conversion rate in material minefields
随机推荐
The super fully automated test learning materials sorted out after a long talk with a Tencent eight year old test all night! (full of dry goods
Future source code view -juc series
不得不会的Oracle数据库知识点(四)
C library function int fprintf (file *stream, const char *format,...) Send formatted output to stream
Idsia & supsi & usi | continuous control behavior learning and adaptive robot operation based on Reinforcement Learning
Cesiumjs 2022^ source code interpretation [8] - resource encapsulation and multithreading
Function: write function fun to find s=1^k+2^k +3^k ++ The value of n^k, (the cumulative sum of the K power of 1 to the K power of n).
1-Redis架构设计到使用场景-四种部署运行模式(上)
基于.NetCore开发博客项目 StarBlog - (14) 实现主题切换功能
Huawei BFD and NQA
51 single chip microcomputer timer 2 is used as serial port
Development of user-defined navigation bar in uniapp
Luogu p1309 Swiss wheel
Summary of JWT related knowledge
查询效率提升10倍!3种优化方案,帮你解决MySQL深分页问题
Conditional test, if, case conditional test statements of shell script
Related configuration commands of Huawei rip
长文综述:大脑中的熵、自由能、对称性和动力学
Introduction to unity shader essentials reading notes Chapter III unity shader Foundation
Summary of common tools and technical points of PMP examination