当前位置:网站首页>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;}}
边栏推荐
- How to use AHAS to ensure the stability of Web services?
- 基于.NetCore开发博客项目 StarBlog - (14) 实现主题切换功能
- Hash table, string hash (special KMP)
- Huawei rip and BFD linkage
- MySQL deadly serial question 2 -- are you familiar with MySQL index?
- Hbuilder link Xiaoyao simulator
- Oracle database knowledge points (IV)
- PMP 考试常见工具与技术点总结
- @EnableAsync @Async
- CesiumJS 2022^ 源码解读[8] - 资源封装与多线程
猜你喜欢

打印菱形图案

Audio resource settings for U3D resource management

Hbuilder link Xiaoyao simulator

A malware detection method for checking PLC system using satisfiability modulus theoretical model

2-redis architecture design to use scenarios - four deployment and operation modes (Part 2)

Hash table, string hash (special KMP)

String hash, find the string hash value after deleting any character, double hash

0 basic learning C language - nixie tube dynamic scanning display

Windos10 reinstallation system tutorial

Solution of cursor thickening
随机推荐
求esp32C3板子连接mssql方法
Day05 table
2-redis architecture design to use scenarios - four deployment and operation modes (Part 2)
Huawei BFD and NQA
Conditional test, if, case conditional test statements of shell script
Query efficiency increased by 10 times! Three optimization schemes to help you solve the deep paging problem of MySQL
Solution of cursor thickening
查询效率提升10倍!3种优化方案,帮你解决MySQL深分页问题
Analysis and solution of lazyinitializationexception
Oracle database knowledge points that cannot be learned (II)
gslb(global server load balance)技术的一点理解
be based on. NETCORE development blog project starblog - (14) realize theme switching function
A dichotomy of Valentine's Day
String hash, find the string hash value after deleting any character, double hash
HackTheBox-baby breaking grad
Pratique technique | analyse et solution des défaillances en ligne (Partie 1)
C import Xls data method summary III (processing data in datatable)
Introduction to unity shader essentials reading notes Chapter III unity shader Foundation
Oracle database knowledge points (I)
CesiumJS 2022^ 源码解读[8] - 资源封装与多线程