真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

PHP中的鉤子是什么?鉤子的機(jī)制原理是什么?

什么是鉤子?

創(chuàng)新互聯(lián)公司2013年開創(chuàng)至今,先為牧野等服務(wù)建站,牧野等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為牧野企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。

大家想必聽過(guò)插件,wordpress插件特別多,這個(gè)就是用鉤子機(jī)制實(shí)現(xiàn)的。

當(dāng)代碼在運(yùn)行的過(guò)程中,我們預(yù)先在運(yùn)行的幾個(gè)特殊點(diǎn)里執(zhí)行一些特殊方法:例如在運(yùn)行方法(例如Blog::add的add方法)之前記錄輸入?yún)?shù)、運(yùn)行方法之后記錄處理結(jié)果,這個(gè)運(yùn)行方法之前、運(yùn)行方法之后就是簡(jiǎn)單的鉤子(掛載點(diǎn)),我們?cè)谶@個(gè)鉤子上放置鉤子函數(shù)(記錄輸入?yún)?shù)、記錄處理結(jié)果),執(zhí)行一些和程序運(yùn)行不相關(guān)的任務(wù)。

add();
Log::write(json_encode($res));

如果在運(yùn)行方法之前放置的是一個(gè)OnBeforeRunActionCallback()的方法,這個(gè)方法可能最開始的時(shí)候是空的,但我們以后就可以不去修改原有代碼,直接在OnBeforeRunActionCallback()里面加代碼邏輯就可以了,例如記錄日志、參數(shù)過(guò)濾等等。

add();
OnAfterRunActionCallback($res);
function OnBeforeRunActionCallback($param){
    Log::write($param);
        FilterParams($param);
}
function OnAfterRunActionCallback($res){
    Log::write(json_encode($res));
}

在項(xiàng)目代碼中,你認(rèn)為要擴(kuò)展(暫時(shí)不擴(kuò)展)的地方放置一個(gè)鉤子函數(shù),等需要擴(kuò)展的時(shí)候,把需要實(shí)現(xiàn)的類和函數(shù)掛載到這個(gè)鉤子上,就可以實(shí)現(xiàn)擴(kuò)展了。

原理

實(shí)際的鉤子一般設(shè)計(jì)為一個(gè)類Hook,該類提供注冊(cè)插件到鉤子(add_hook)、觸發(fā)鉤子方法(trigger_hook)。注冊(cè)插件的時(shí)候?qū)⒉寮\(yùn)行的可執(zhí)行方法存儲(chǔ)到鉤子對(duì)應(yīng)的數(shù)組里面。

$_listeners = array(
    'OnBeforeRunAction' => array(
        'callback1',
        'callback2',
        'callback3',
    ),
);
//提前注冊(cè)插件到鉤子
add_hook('OnBeforeRunAction', 'callback4');
//特定地方執(zhí)行鉤子
trigger_hook('OnBeforeRunAction');

當(dāng)觸發(fā)鉤子的時(shí)候,將遍歷OnBeforeRunAction里注冊(cè)的回調(diào)方法,執(zhí)行對(duì)應(yīng)的回調(diào)方法,實(shí)現(xiàn)動(dòng)態(tài)擴(kuò)展功能。注冊(cè)的鉤子方法一般是匿名函數(shù):

function trigger_hook($hook, $data=''){
    //查看要實(shí)現(xiàn)的鉤子,是否在監(jiān)聽數(shù)組之中
    if (isset($this->_listeners[$hook]) && is_array($this->_listeners[$hook]) && count($this->_listeners[$hook]) > 0)
    {
        // 循環(huán)調(diào)用開始
        foreach ($this->_listeners[$hook] as $listener)
        {
            if(is_callable()){
                call_user_func($listener, $data);
            }elseif(is_array($listener)){
                // 取出插件對(duì)象的引用和方法
                $class =& $listener[0];
                $method = $listener[1];
                if(method_exists($class,$method))
                {
                    // 動(dòng)態(tài)調(diào)用插件的方法
                    $class->$method($data);
                }
            }
        }
    }
}

如何實(shí)現(xiàn)?

簡(jiǎn)單的

1、插件類Hook:提供注冊(cè)插件和執(zhí)行插件的方法,實(shí)際是往一個(gè)數(shù)組里存掛載點(diǎn)對(duì)應(yīng)的可執(zhí)行方法。

2、在某個(gè)配置文件或者函數(shù)里統(tǒng)一注冊(cè)插件。

class Hook
{
    //action hooks array  
    private static $actions = array();
    /**
     * ads a function to an action hook
     * @param $hook
     * @param $function
     */
    public static function add_action($hook,$function)
    {   
        $hook=mb_strtolower($hook,CHARSET);
        // create an array of function handlers if it doesn't already exist
        if(!self::exists_action($hook))
        {
            self::$actions[$hook] = array();
        }
        // append the current function to the list of function handlers
        if (is_callable($function))
        {
            self::$actions[$hook][] = $function;
            return TRUE;
        }
        return FALSE ;
    }
    /**
     * executes the functions for the given hook
     * @param string $hook
     * @param array $params
     * @return boolean true if a hook was setted
     */
    public static function do_action($hook,$params=NULL)
    {
        $hook=mb_strtolower($hook,CHARSET);
        if(isset(self::$actions[$hook]))
        {
            // call each function handler associated with this hook
            foreach(self::$actions[$hook] as $function)
            {
                if (is_array($params))
                {
                    call_user_func_array($function,$params);
                }
                else
                {
                    call_user_func($function);
                }
                //cant return anything since we are in a loop! dude!
            }
            return TRUE;
        }
        return FALSE;
    }
    /**
     * gets the functions for the given hook
     * @param string $hook
     * @return mixed
     */
    public static function get_action($hook)
    {
        $hook=mb_strtolower($hook,CHARSET);
        return (isset(self::$actions[$hook]))? self::$actions[$hook]:FALSE;
    }
    /**
     * check exists the functions for the given hook
     * @param string $hook
     * @return boolean
     */
    public static function exists_action($hook)
    {
        $hook=mb_strtolower($hook,CHARSET);
        return (isset(self::$actions[$hook]))? TRUE:FALSE;
    }
}
 
    /**
     * Hooks Shortcuts not in class
     */
    function add_action($hook,$function)
    {
        return Hook::add_action($hook,$function);
    }
 
    function do_action($hook)
    {
        return Hook::do_action($hook);
    }

用法舉例:

//添加鉤子
Hook::add_action('unique_name_hook','some_class::hook_test');
//或使用快捷函數(shù)添加鉤子:
add_action('unique_name_hook','other_class::hello');
add_action('unique_name_hook','some_public_function');
//執(zhí)行鉤子
do_action('unique_name_hook');//也可以使用 Hook::do_action();

帶安裝/卸載的

鉤子類初始化的時(shí)候去注冊(cè)已經(jīng)開啟的插件(如數(shù)據(jù)庫(kù)記錄);全局合適的時(shí)候設(shè)置掛載點(diǎn);運(yùn)行到合適的時(shí)候觸發(fā)掛載點(diǎn)注冊(cè)的事件。

1、插件類Hook:提供注冊(cè)插件和執(zhí)行插件的方法,實(shí)際是往一個(gè)數(shù)組里存掛載點(diǎn)對(duì)應(yīng)的可執(zhí)行方法。

2、插件類增加一個(gè)初始化的方法,去數(shù)據(jù)查找已經(jīng)安裝的插件,運(yùn)行插件必須執(zhí)行的注冊(cè)方法(reg),注冊(cè)插件方法注冊(cè)鉤子到掛載點(diǎn)。

3、固定把插件放在某個(gè)目錄,并安照一定規(guī)范寫配置文件。后臺(tái)有插件列表頁(yè)面,遍歷指定目錄下的插件。當(dāng)安裝的時(shí)候,將插件信息記錄到數(shù)據(jù)庫(kù),卸載的時(shí)候刪除數(shù)據(jù)庫(kù)記錄信息。

query("is_open = 1","class_name","sort asc");
        //加載默認(rèn)插件
        foreach(self::$defaultList as $val)
        {
            $pluginList[]= array('class_name' => $val);
        }
        foreach($pluginList as $key => $val)
        {
            $className = $val['class_name'];
            $classFile = self::path().$className."/".$className.".php";
            if(is_file($classFile))
            {
                include_once($classFile);
                $pluginObj = new $className();
                $pluginObj->reg();
            }
        }
    }
    /**
     * @brief 注冊(cè)事件
     * @param string $event 事件
     * @param object ro function $classObj 類實(shí)例 或者 匿名函數(shù)
     * @param string $method 方法名字
     */
    public static function reg($event,$classObj,$method = "")
    {
        if(!isset(self::$_listen[$event]))
        {
            self::$_listen[$event] = array();
        }
        self::$_listen[$event][] = array($classObj,$method);
    }
    /**
     * @brief 顯示已注冊(cè)事件
     * @param string $event 事件名稱
     * @return array
     */
    public static function get($event = '')
    {
        if($event)
        {
            if( isset(self::$_listen[$event]) )
            {
                return self::$_listen[$event];
            }
            return null;
        }
        return self::$_listen;
    }
    /**
     * @brief 觸發(fā)事件
     * @param string $event 事件
     * @param mixed  $data  數(shù)據(jù)
     * @notice 可以調(diào)用匿名函數(shù)和方法
     */
    public static function trigger($event,$data = null)
    {
        $result = array();
        if(isset(self::$_listen[$event]))
        {
            foreach(self::$_listen[$event] as $key => $val)
            {
                list($pluginObj,$pluginMethod) = $val;
                $result[$key] = is_callable($pluginObj) ? call_user_func($pluginObj,$data):call_user_func(array($pluginObj,$pluginMethod),$data);
            }
        }
        return isset($result[1]) ? $result : current($result);
    }
    /**
     * @brief 插件物理路徑
     * @return string 路徑字符串
     */
    public static function path()
    {
        return IWeb::$app->getBasePath()."plugins/";
    }
    /**
     * @brief 插件WEB路徑
     * @return string 路徑字符串
     */
    public static function webPath()
    {
        return IUrl::creatUrl('')."plugins/";
    }
    /**
     * @brief 獲取全部插件
     * @param string $name 插件名字,如果為空則獲取全部插件信息
     * @return array 插件信息 array(
        "name"        => 插件名字,
        "description" => 插件描述,
        "explain"     => 使用說(shuō)明,
        "class_name"  => 插件ID,
        "is_open"     => 是否開啟,
        "is_install"  => 是否安裝,
        "config_name" => 默認(rèn)插件參數(shù)結(jié)構(gòu),
        "config_param"=> 已經(jīng)保存的插件參數(shù),
        "sort"        => 排序,
     )
     */
    public static function getItems($name = '')
    {
        $result = array();
        $dirRes = opendir(self::path());
        //遍歷目錄讀取配置文件
        $pluginDB = new IModel('plugin');
        while($dir = readdir($dirRes))
        {
            if($dir[0] == "." || $dir[0] == "_")
            {
                continue;
            }
            if($name && $result)
            {
                break;
            }
            if($name && $dir != $name)
            {
                continue;
            }
            $pluginIndex = self::path().$dir."/".$dir.".php";
            if(is_file($pluginIndex))
            {
                include_once($pluginIndex);
                if(get_parent_class($dir) == "pluginBase")
                {
                    $class_name   = $dir;
                    $pluginRow    = $pluginDB->getObj('class_name = "'.$class_name.'"');
                    $is_open      = $pluginRow ? $pluginRow['is_open'] : 0;
                    $is_install   = $pluginRow ? 1                     : 0;
                    $sort         = $pluginRow ? $pluginRow['sort']    : 99;
                    $config_param = array();
                    if($pluginRow && $pluginRow['config_param'])
                    {
                        $config_param = JSON::decode($pluginRow['config_param']);
                    }
                    $result[$dir] = array(
                        "name"        => $class_name::name(),
                        "description" => $class_name::description(),
                        "explain"     => $class_name::explain(),
                        "class_name"  => $class_name,
                        "is_open"     => $is_open,
                        "is_install"  => $is_install,
                        "config_name" => $class_name::configName(),
                        "config_param"=> $config_param,
                        "sort"        => $sort,
                    );
                }
            }
        }
        if(!$name)
        {
            return $result;
        }
        return isset($result[$name]) ? $result[$name] : array();
    }
    /**
     * @brief 系統(tǒng)內(nèi)置的所有事件觸發(fā)
     */
    public static function onCreateApp(){plugin::init();plugin::trigger("onCreateApp");}
    public static function onFinishApp(){plugin::trigger("onFinishApp");}
    public static function onBeforeCreateController($ctrlId){plugin::trigger("onBeforeCreateController",$ctrlId);plugin::trigger("onBeforeCreateController@".$ctrlId);}
    public static function onCreateController($ctrlObj){plugin::trigger("onCreateController");plugin::trigger("onCreateController@".$ctrlObj->getId());}
    public static function onFinishController($ctrlObj){plugin::trigger("onFinishController");plugin::trigger("onFinishController@".$ctrlObj->getId());}
    public static function onBeforeCreateAction($ctrlObj,$actionId){plugin::trigger("onBeforeCreateAction",$actionId);plugin::trigger("onBeforeCreateAction@".$ctrlObj->getId());plugin::trigger("onBeforeCreateAction@".$ctrlObj->getId()."@".$actionId);}
    public static function onCreateAction($ctrlObj,$actionObj){plugin::trigger("onCreateAction");plugin::trigger("onCreateAction@".$ctrlObj->getId());plugin::trigger("onCreateAction@".$ctrlObj->getId()."@".$actionObj->getId());}
    public static function onFinishAction($ctrlObj,$actionObj){plugin::trigger("onFinishAction");plugin::trigger("onFinishAction@".$ctrlObj->getId());plugin::trigger("onFinishAction@".$ctrlObj->getId()."@".$actionObj->getId());}
    public static function onCreateView($ctrlObj,$actionObj){plugin::trigger("onCreateView");plugin::trigger("onCreateView@".$ctrlObj->getId());plugin::trigger("onCreateView@".$ctrlObj->getId()."@".$actionObj->getId());}
    public static function onFinishView($ctrlObj,$actionObj){plugin::trigger("onFinishView");plugin::trigger("onFinishView@".$ctrlObj->getId());plugin::trigger("onFinishView@".$ctrlObj->getId()."@".$actionObj->getId());}
    public static function onPhpShutDown(){plugin::trigger("onPhpShutDown");}
}
/**
 * @brief 插件基類,所有插件必須繼承此類
 * @notice 必須實(shí)現(xiàn)3個(gè)抽象方法: reg(),name(),description()
 */
abstract class pluginBase extends IInterceptorBase
{
    //錯(cuò)誤信息
    protected $error = array();
    //注冊(cè)事件接口,內(nèi)部通過(guò)調(diào)用payment::reg(事件,對(duì)象實(shí)例,方法);
    public function reg(){}
    /**
     * @brief 默認(rèn)插件參數(shù)信息,寫入到plugin表config_param字段
     * @return array("字段名" => array(
         "name"    => "文字顯示",
         "type"    => "數(shù)據(jù)類型【text,radio,checkbox,select】",
         "pattern" => "數(shù)據(jù)校驗(yàn)【int,float,date,datetime,require,正則表達(dá)式】",
         "value"   => "1,數(shù)組:枚舉數(shù)據(jù)【radio,checkbox,select】的預(yù)設(shè)值,array(名字=>數(shù)據(jù)); 2,字符串:【text】默認(rèn)數(shù)據(jù)",
        ))
     */
    public static function configName()
    {
        return array();
    }
    /**
     * @brief 插件安裝
     * @return boolean
     */
    public static function install()
    {
        return true;
    }
    /**
     * @brief 插件卸載
     * @return boolean
     */
    public static function uninstall()
    {
        return true;
    }
    /**
     * @brief 插件名字
     * @return string
     */
    public static function name()
    {
        return "插件名稱";
    }
    /**
     * @brief 插件功能描述
     * @return string
     */
    public static function description()
    {
        return "插件描述";
    }
    /**
     * @brief 插件使用說(shuō)明
     * @return string
     */
    public static function explain()
    {
        return "";
    }
    /**
     * @brief 獲取DB中錄入的配置參數(shù)
     * @return array
     */
    public function config()
    {
        $className= get_class($this);
        $pluginDB = new IModel('plugin');
        $dataRow  = $pluginDB->getObj('class_name = "'.$className.'"');
        if($dataRow && $dataRow['config_param'])
        {
            return JSON::decode($dataRow['config_param']);
        }
        return array();
    }
    /**
     * @brief 返回錯(cuò)誤信息
     * @return array
     */
    public function getError()
    {
        return $this->error ? join("\r\n",$this->error) : "";
    }
    /**
     * @brief 寫入錯(cuò)誤信息
     * @return array
     */
    public function setError($error)
    {
        $this->error[] = $error;
    }
    /**
     * @brief 插件視圖渲染有布局
     * @param string $view 視圖名字
     * @param array  $data 視圖里面的數(shù)據(jù)
     */
    public function redirect($view,$data = array())
    {
        if($data === true)
        {
            $this->controller()->redirect($view);
        }
        else
        {
            $__className      = get_class($this);
            $__pluginViewPath = plugin::path().$__className."/".$view;
            $result = self::controller()->render($__pluginViewPath,$data);
            if($result === false)
            {
                IError::show($__className."/".$view."插件視圖不存在");
            }
        }
    }
    /**
     * @brief 插件視圖渲染去掉布局
     * @param string $view 視圖名字
     * @param array  $data 視圖里面的數(shù)據(jù)
     */
    public function view($view,$data = array())
    {
        self::controller()->layout = "";
        $this->redirect($view,$data);
    }
    /**
     * @brief 插件物理目錄
     * @param string 插件路徑地址
     */
    public function path()
    {
        return plugin::path().get_class($this)."/";
    }
    /**
     * @brief 插件WEB目錄
     * @param string 插件路徑地址
     */
    public function webPath()
    {
        return plugin::webPath().get_class($this)."/";
    }
}

以上就是PHP鉤子機(jī)制原理及詳解的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注創(chuàng)新互聯(lián)其它相關(guān)文章!


文章標(biāo)題:PHP中的鉤子是什么?鉤子的機(jī)制原理是什么?
標(biāo)題鏈接:http://weahome.cn/article/iigsic.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部