zoukankan      html  css  js  c++  java
  • php钩子原理和实现

    5.3以下和5.3以上的版本在PHP类与对象区别很大,请注意

    其实原理很简单,有些人把事情弄的过于发杂,其实就是调用某个目录下的比如/hook目录下注册在hook函数里面和读取hook配置文件里面的类的方法的一个调用类的方法的功能

    目的就是最少改动代码,改动旧功能,或者增加一些新功能,或者简单说成调用函数都行

    但是读取hook的配置文件,还是需要在系统的里面每次都需要读取,其实就失去了hook的意义,建议只做钩子本身的就好

     参看一下ci的hook,仅截取hook函数核心部分

    复制代码
    <?php
     protected function _run_hook($data) {
            // Closures/lambda functions and array($object, 'method') callables
            if (is_callable($data)) {
                is_array($data) ? $data[0]->{$data[1]}() : $data();
    
                return TRUE;
            } elseif (!is_array($data)) {
                return FALSE;
            }
    
            if ($this->_in_progress === TRUE) {
                return;
            }
    
            if (!isset($data['filepath'], $data['filename'])) {
                return FALSE;
            }
    
            $filepath = APPPATH . $data['filepath'] . '/' . $data['filename'];
    
            if (!file_exists($filepath)) {
                return FALSE;
            }
            $class = empty($data['class']) ? FALSE : $data['class'];
            $function = empty($data['function']) ? FALSE : $data['function'];
            $params = isset($data['params']) ? $data['params'] : '';
    
            if (empty($function)) {
                return FALSE;
            }
    
            // Set the _in_progress flag
            $this->_in_progress = TRUE;
    
            // Call the requested class and/or function
            if ($class !== FALSE) {
                // The object is stored?
                if (isset($this->_objects[$class])) {
                    if (method_exists($this->_objects[$class], $function)) {
                        $this->_objects[$class]->$function($params);
                    } else {
                        return $this->_in_progress = FALSE;
                    }
                } else {
                    class_exists($class, FALSE) OR require_once($filepath);
    
                    if (!class_exists($class, FALSE) OR ! method_exists($class, $function)) {
                        return $this->_in_progress = FALSE;
                    }
    
                    // Store the object and execute the method
                    $this->_objects[$class] = new $class(); 
                    $this->_objects[$class]->$function($params);
    核心部分 读取参数部分,去实例化类调用方法 传递参数 其实这也是MVC url路由实现的核心,现在很多
    //都是使用 call_user_func_array call_user_func 这两个方法
    } } else { function_exists($function) OR require_once($filepath); if (!function_exists($function)) { return $this->_in_progress = FALSE; } $function($params); } $this->_in_progress = FALSE; return TRUE; }
    复制代码

    原理图解

    个人实现版本

     如果你觉得麻烦,甚至可以写个方法都行,建议写成一个类,因为有些东西需要更多的信息

    1.php

    复制代码
    include 'hook.class.php';
    
    $rr = new hook();
    //$ee = $rr->get_all_class();
    
    $rr->run_hook('ff','ss',array());
    //echo '<pre>';
    //print_r($ee);
    //echo '</pre>';
    复制代码

    hook.class.php

    复制代码
    class hook {
    
        public $HOOK_PATH;
        public $PATH; //完整钩子文件目录
        public $object;
    
        //调用的时候这个类使用的时候,必须在系统的执行流程当中
        public function __construct() {
    
            $this->HOOK_PATH = ''; //项目的路径,根据你的项目计算路径  
            $current_path = str_replace("\", "/", getcwd()); //获取当前目录
            //这个地方在实际用的时候看你需要调整
            $this->PATH = $current_path . $this->HOOK_PATH;
        }
    
        /* 注册钩子 也可以叫做运行钩子
         * $class       类名称
         * $function    方法 
         * $param       方法参数
         */
    
        public function run_hook($class, $function, $param = array()) {
            include $this->PATH . '/' . $class . '.class.php';
    //        var_dump($this->PATH . '/' . $class . '.class.php');
    //        call_user_func_array(array($class, $function), $param);//只能调用类的静态方法
    //        call_user_func(array($class, $function), $param);  //只能调用类的静态方法
    //        其他写法
            $this->object = new $class();
            $this->object->$function($param); //这样就可以不用调用静态方法
        }
    
        //返回当前已经所有的钩子类和方法  不要当前方法调用这个核心类,需要稍微改造,在$hook_array[$key]['function']的返回方法名的时候
        public function get_all_class() {
            //搜寻hook目录下的所有钩子文件,返回数组
    //        $this->PATH
    //        var_dump($this->PATH);
            $file_array = scandir($this->PATH);
            $hook_array = array();
            foreach ($file_array as $key => $value) {
                if (strpos($value, '.class.php') == true) {     //扫描路径绝对不能和这个类本身在一个同一个目录下,不然会出现重复声明的同名类
                    $name = explode('.', $value);
                    $hook_array[$key]['name'] = $name['0'] . '钩子类';
                    $hook_array[$key]['url'] = $this->PATH . '/' . $value;
    //                include $hook_array[$key]['url']; 
    //                $cc = new $name['0']();
    //                $hook_array[$key]['function'][] = get_class_methods($cc);
    // $hook_array[$key]['function']['param'][] = get_class_vars($class_name); //获取方法变量
    } } return $hook_array; } }
    复制代码

    调用的某个类名

    ff.class.php 的ss方法

        public function ss() {
    //    static public function ss() {
            echo 'dddddddddddddddddddd';
        }

    另一个版本

    更方便调用

    复制代码
    class hooks {
    
        const Directory_Structure = '/hooks/'; //相对目录的路径  具体项目使用的时候需要调整
    
        static public function get_path() {
            return str_replace("\", "/", getcwd());
        }
    
        static public function run_hook($class, $function, $param = array()) {
           $s =  include self::get_path() . self::Directory_Structure .$class. '.class.php';
    
            call_user_func(array($class, $function), $param);  //只能调用类的静态方法
    //        其他写法
    //        $object = new $class();
    //        $object->$function($param); //这样就可以不用调用静态方法
        }
    
    }
    复制代码

    使用

    复制代码
    include 'hooks.class.php';
    
    hooks::run_hook('ee', 'vv',$param =array());

    当然也可以这么访问

    $foo = new hooks();

    $foo->run_hook('ee', 'vv',array());

    $foo::run_hook('ee', 'vv',array());

    自 PHP 5.3.0 起,可以用一个变量来动态调用类。但该变量的值不能为关键字 selfparent 或 static

    复制代码

     钩子是比较灵活的,可以额外增加一个功能代码,使代码更整洁,比如在做什么一些重要操作,创建订单,在创建订单之前需要做些什么,在创建之后做些什么,都可以使用钩子

    这样代码更加灵活

  • 相关阅读:
    shell截取字符串的方法
    安装sql server managerment studio报错"The instance id is required but it is missing"
    windows 80端口被占用的解决方法
    centos如何安装软件
    ORA-00257归档日志写满的解决方法
    VCenter克隆虚拟机报错msg.snapshot.error-QUIESCINGERROR
    如何启动或关闭oracle的归档(ARCHIVELOG)模式
    ubuntu下nagios配置
    vsphere vcenter server下安装ubuntu的vmwaretools
    virtualbox迁移至vcenter/vmware workstation
  • 原文地址:https://www.cnblogs.com/raobenjun/p/8032376.html
Copyright © 2011-2022 走看看