之前对钩子还是有点感兴趣,写下了之前的设计模式,顺手看了钩子,其实你可以比对看一下。


钩子和我上一篇的观察者模式或者策略模式很有关联,应该就是相通的。


应用场景:来之TP行为的文字---》框架的执行流程中,例如路由检测是一个行为,静态缓存是一个行为,用户权限检测也是行为,大到业务逻辑,小到浏览器检测、多语言检测等等都可以当做是一个行为,甚至说你希望给你的网站用户的第一次访问弹出Hello,world!这些都可以看成是一种行为,行为的存在让你无需改动框架和应用,而在外围通过扩展或者配置来改变或者增加一些功能。

外加一幅图:竟然需要用Flash来上传图片,可惜浏览器不支持,我也很讨厌Flash。那么就没办法来打字吧。钩子程序对于我最大的体验就是我第一次和老板做一个简单的手机编辑器,注册缴费使用,所以每个页面都要手动写下固定的代码,验证是否缴费。所以每个页面雷打不动的几行代码,如今觉得可以使用钩子或者说钩子应运而生。如果你也遇到这种情景,就可以考略,当然,写了钩子,也许你还需要每个地方写一下,引用下,但是你对于验证的程序实现的维护就很方便了。TP的行为更进一步,在整个框架的几个关键点设置了标签,之要绑定行为就可以。


帮你理解狗子的小程序如下:

<?php//统一对外的类classHook{private$hooklist=null;//感觉这里很像观察者模式或者是策略模式publicfunctionadd($action_hook){$this->hooklist[]=new$action_hook();}//触发事件publicfunctionexec(){foreach($this->hooklistas$action_hook){$action_hook->act();//钩子中统一的方法}}}//不同用途的钩子具体对象,比如说验证密码,验证权限,统一加密等等,classaction_hook_1{publicfunctionact(){echo"我来做第一件事";}}classaction_hook_2{publicfunctionact(){echo"我来做第2件事";}}classaction_hook_3{publicfunctionact(){echo"我来做第3件事";}}//需要绑定钩子的具体对象classBall{publicfunctiondown(){echo'我需要做一些通用的验证工作';//注册事件,这里就可以加载相应的钩子类,因为在一个文件,直接使用$hook=newHook();$hook->add("action_hook_1");$hook->add("action_hook_2");$hook->add("action_hook_3");$hook->exec();}//淡然也可以注册完就直接执行钩子,也可以写到单独方法publicfunctionexec(){}}$ball=newBall();$ball->down();

估计看完这个你应该可以理解八九不离十。不理解也没关系,这并不影响你的程序书写,过段时间 再看估计就懂了,不着急。


然后TP里面的Hook类我也附录在后面,方法都是通用的listen,add注册,run执行,然后在相应的命名空间写下你的钩子想要实现的具体代码。然后TP主要是利用配置文件来进行说明各个文件的关系,这个是很不错,也是需要学习,也是很新手容易困惑的地方。(这件事我想当推荐看手册,不用看杂七乱八的文章TP5.0的行为在扩展里面)思路就是这样了。


附录:TP hook类

<?php//+----------------------------------------------------------------------//|ThinkPHP[WECANDOITJUSTTHINK]//+----------------------------------------------------------------------//|Copyright(c)2006~2017http://thinkphp.cnAllrightsreserved.//+----------------------------------------------------------------------//|Licensed(http://www.apache.org/licenses/LICENSE-2.0)//+----------------------------------------------------------------------//|Author:liu21st<liu21st@gmail.com>//+----------------------------------------------------------------------namespacethink;classHook{privatestatic$tags=[];/***动态添加行为扩展到某个标签*@paramstring$tag标签名称*@parammixed$behavior行为名称*@parambool$first是否放到开头执行*@returnvoid*/publicstaticfunctionadd($tag,$behavior,$first=false){isset(self::$tags[$tag])||self::$tags[$tag]=[];if(is_array($behavior)&&!is_callable($behavior)){if(!array_key_exists('_overlay',$behavior)||!$behavior['_overlay']){unset($behavior['_overlay']);self::$tags[$tag]=array_merge(self::$tags[$tag],$behavior);}else{unset($behavior['_overlay']);self::$tags[$tag]=$behavior;}}elseif($first){array_unshift(self::$tags[$tag],$behavior);}else{self::$tags[$tag][]=$behavior;}}/***批量导入插件*@paramarray$tags插件信息*@paramboolean$recursive是否递归合并*/publicstaticfunctionimport(array$tags,$recursive=true){if($recursive){foreach($tagsas$tag=>$behavior){self::add($tag,$behavior);}}else{self::$tags=$tags+self::$tags;}}/***获取插件信息*@paramstring$tag插件位置留空获取全部*@returnarray*/publicstaticfunctionget($tag=''){if(empty($tag)){//获取全部的插件信息returnself::$tags;}else{returnarray_key_exists($tag,self::$tags)?self::$tags[$tag]:[];}}/***监听标签的行为*@paramstring$tag标签名称*@parammixed$params传入参数*@parammixed$extra额外参数*@parambool$once只获取一个有效返回值*@returnmixed*/publicstaticfunctionlisten($tag,&$params=null,$extra=null,$once=false){$results=[];$tags=static::get($tag);foreach($tagsas$key=>$name){$results[$key]=self::exec($name,$tag,$params,$extra);if(false===$results[$key]){//如果返回false则中断行为执行break;}elseif(!is_null($results[$key])&&$once){break;}}return$once?end($results):$results;}/***执行某个行为*@parammixed$class要执行的行为*@paramstring$tag方法名(标签名)*@paramMixed$params传人的参数*@parammixed$extra额外参数*@returnmixed*/publicstaticfunctionexec($class,$tag='',&$params=null,$extra=null){App::$debug&&Debug::remark('behavior_start','time');$method=Loader::parseName($tag,1,false);if($classinstanceof\Closure){$result=call_user_func_array($class,[&$params,$extra]);$class='Closure';}elseif(is_array($class)){list($class,$method)=$class;$result=(new$class())->$method($params,$extra);$class=$class.'->'.$method;}elseif(is_object($class)){$result=$class->$method($params,$extra);$class=get_class($class);}elseif(strpos($class,'::')){$result=call_user_func_array($class,[&$params,$extra]);}else{$obj=new$class();$method=($tag&&is_callable([$obj,$method]))?$method:'run';$result=$obj->$method($params,$extra);}if(App::$debug){Debug::remark('behavior_end','time');Log::record('[BEHAVIOR]Run'.$class.'@'.$tag.'[RunTime:'.Debug::getRangeTime('behavior_start','behavior_end').'s]','info');}return$result;}}