Hook技术及PHP实现

2018-03-06 16:17:05 PHP 阅读: 773

目前很多框架和系统基本都加入了Hook功能,如:tp,levavel,wordpres等 。因此也在我的PHP框架加入了Hook模块。

PHP

什么是Hook

百度百科中的解释:

Hook是Windows中提供的一种用以替换DOS下“中断”的系统机制,中文译为“挂钩”或“钩子”。在对特定的系统事件进行hook后,一旦发生已hook事件,对该事件进行hook的程序就会收到系统的通知,这时程序就能在第一时间对该事件做出响应。

虽然这段话说的是windows编程下的,但在PHP中也是类似的。
我的理解是:Hook是一种的插件机制,通过在‘钩子’上挂载一些行为(函数或者类方法,也可以说是插件),最后在需要的地方可以通过这个‘钩子’来执行这些行为。
这种技术很有用,特别是在框架中,框架中预先设计一些钩子放在合适的位置,开发者可以将自己需要的一些功能放置在这些钩子上,当系统运行到钩子放置的位置时,会自动执行这些行为。

PHP中的实现

没看懂概念的可以看看下面代码,看看输出结果。

Hook.php

<?php
/**
 * @description Hook类
 * @author      luoluolzb
 */

class Hook
{
    /**
     * 钩子列表
     * @var array
     */
    protected static $hooks = [];

    /**
     * 批量导入钩子
     * @param  array $data
     */
    public static function import($data)
    {
        foreach ($data as $name => $behaviors) {
            self::register($name, $behaviors);
        }
    }

    /**
     * 在一个钩子下挂载一个或多个行为
     * @param  string $name   钩子名称
     * @param  string $plugin 行为类名
     */
    public static function register($name, $behaviors)
    {
        isset(self::$hooks[$name]) || self::$hooks[$name] = [];
        if (is_array($behaviors)) {
            foreach ($behaviors as $behavior) {
                self::_register($name, $behavior);
            }
        } else {
            self::_register($name, $behaviors);
        }
    }

    /**
     * 在一个钩子下挂载一个行为
     * @param  string $name   钩子名称
     * @param  string $plugin 行为类名
     */
    protected static function _register($name, $behavior)
    {
        if (!class_exists($behavior)) {
            throw new RuntimeException("Hook '{$behavior}' Not Found!'");
        }
        self::$hooks[$name][] = new $behavior;
    }

    /**
     * 触发一个钩子下的行为(按注册顺序执行)
     * @param  string $name   钩子名称
     * @param  array  $params 传入参数
     * @return mixed
     */
    public static function trigger($name, $params = [])
    {
        if (isset(self::$hooks[$name])) {
            foreach (self::$hooks[$name] as &$behavior) {
                call_user_func_array([$behavior, 'exec'], $params);
            }
        }
    }
}

test.php

<?php

require __DIR__ . '/Hook.php';

//以下是三个行为插件
//必须都实现exec函数
//同一个钩子下的插件的exec函数参数定义需保持一致

class SayHello
{
    public function exec()
    {
        echo 'Hello';
        echo "\n";
    }
}

class SayWorld
{
    public function exec()
    {
        echo 'World';
        echo "\n";
    }
}

class SayName
{
    public function exec($name)
    {
        echo $name;
        echo "\n";
    }
}

//挂载单个钩子
Hook::register('say1', 'SayHello');
Hook::register('say2', 'SayWorld');
Hook::register('say3', ['SayWorld', 'SayHello']);

//挂载多个钩子
Hook::register('say4', ['SayName', 'SayName']);

//批量导入多个钩子
Hook::import([
    'say2' => ['SayWorld', 'SayHello'],
    'say1' => ['SayHello', 'SayWorld'],
]);

//触发钩子
Hook::trigger('say1');
Hook::trigger('say2');
Hook::trigger('say3');
Hook::trigger('say4', ['luoluolzb']);

执行结果

Hello
Hello
World
World
World
Hello
World
Hello
luoluolzb
luoluolzb

版权声明:本文为博主原创文章,转载需注明来自: 洛洛の空间


功能
最新评论