编程中的术语“钩子”是什么意思?

时间:2009-01-21 23:52:52

标签: hook

我最近在与一些人谈论我正在编写的程序时听到了“钩子”一词。虽然我从对话中推断钩子是一种函数,但我不确定这个术语的含义。我搜索了一个定义,但无法找到一个好的答案。有人能够让我知道这个术语通常意味着什么,也许是一个小例子来说明这个定义吗?

13 个答案:

答案 0 :(得分:131)

基本上,它是代码中的一个位置,允许您点击模块以提供不同的行为或在发生某些事情时作出反应。

答案 1 :(得分:70)

钩子是由软件提供的功能,用于该软件的用户在某些情况下调用自己的代码。该代码可以扩充或替换当前代码。

在过去,计算机真正是个人化的,病毒不那么流行(我说的是80年代),就像修补操作系统软件本身来调用你的代码一样简单。我记得在Apple II上编写了Applesoft BASIC语言的扩展,它简单地将我的代码连接到BASIC解释器,方法是在处理任何一行之前调用我的代码。

有些计算机有预先设计的钩子,其中一个例子是Apple II上的I / O流。它使用这样的钩子来注入整个磁盘子系统(Apple II ROM最初是在盒式磁带是PC的主要存储介质的时代制造的)。您通过打印 ASCII代码4(CTRL-D)控制磁盘,然后是您要执行的命令,然后是CR,它被磁盘子系统拦截,它已经融入Apple ROM打印例程。

例如,行:

PRINT CHR(4);"CATALOG"
PRINT CHR(4);"IN#6"

将列出磁盘内容,然后重新初始化计算机。这允许通过将第一行设置为:

来保护您的BASIC程序
123 REM XIN#6

然后使用POKECTRL-D所在的位置插入X字符。然后,任何试图列出你的源的人都会通过输出例程发送重新初始化序列,磁盘子系统会检测它。

这通常是我们不得不诉诸的诡计,以获得我们想要的行为。

如今,随着操作系统更加安全,它为钩子本身提供了便利,因为您不再需要“在飞行中”或在磁盘上修改操作系统。

他们已经在很长的时间了。大型机有它们(称为出口),大量的大型机软件甚至现在也使用这些设备。例如,z / OS附带的免费源代码控制系统(称为SCLM)允许您通过简单地将自己的代码放在出口中来完全替换安全子系统。

答案 2 :(得分:37)

从一般意义上讲,“钩子”可以让你,程序员,查看和/或交互和/或改变系统/程序中已经发生的事情。

例如,Drupal CMS为开发人员提供了钩子,让他们在创建“内容节点”后采取其他操作。如果开发人员没有实现钩子,则按正常方式创建节点。如果开发人员实现了一个钩子,那么只要创建一个节点,他们就可以运行一些额外的代码。此代码可以执行任何操作,包括回滚和/或更改原始操作。它也可以完全与节点创建无关。

回调可以被认为是一种特定的钩子。通过在系统中实现回调功能,该系统允许您在操作完成后调用一些其他代码。但是,挂钩(作为通用术语)不仅限于回调。

另一个例子。有时Web开发人员会将元素上的类名和/或ID称为钩子。这是因为通过将ID /类名放在元素上,然后他们可以使用Javascript来修改该元素,或者“挂钩”到页面文档。 (这是延伸意义,但它是常用的,值得一提)

答案 3 :(得分:15)

Hooks是一类功能,允许基本代码调用扩展代码。这在核心开发人员希望提供可扩展性而不暴露其代码的情况下非常有用。

钩子的一种用法是在视频游戏mod开发中。游戏可能不允许mod开发人员扩展基本功能,但是核心mod库开发人员可以添加钩子。通过这些钩子,独立开发人员可以根据任何所需事件调用自定义代码,例如游戏加载,库存更新,实体交互等。

一种常见的实现方法是为函数提供一个空的回调列表,然后公开扩展回调列表的能力。基本代码将始终在相同和适当的时间调用该函数,但是,使用空回调列表,该函数不执行任何操作。这是设计的。

然后,第三方有机会编写其他代码并将其新回调添加到hook的回调列表中。除了可用钩子的参考之外,它们还以最小的风险扩展了基本系统。

Hooks不允许开发人员做任何其他结构和接口无法完成的事情。考虑到任务和用户(第三方开发人员),可以选择它们。

为了澄清:钩子允许扩展,可以使用回调来实现。回调通常只是一个函数指针;计算的函数地址。其他答案/评论似乎有些混乱。

答案 4 :(得分:14)

编程中的

Hooking是一种采用所谓的钩子将一系列程序作为事件处理程序的技术。

答案 5 :(得分:11)

简单地说:

钩子是在现有代码之前,之后或代替现有代码执行自定义代码(函数)的一种方法。例如,可以编写一个函数来“挂钩”到登录过程中,以便在继续正常登录过程之前执行Captcha函数。

答案 6 :(得分:4)

Hook表示代码中您调度某种类型事件的位置,如果此事件之前已使用适当的函数进行回调注册,那么它将由此注册函数处理,否则不会发生任何事情。

答案 7 :(得分:2)

遇到某些条件时,可以执行

挂钩。例如调用某些变量或某些操作或发生某些事件。钩子可以进入过程并改变事物或对变化做出反应。

答案 8 :(得分:1)

通常挂钩是指Win32 message hooking或Linux / OSX等价物,但更通用的挂钩只是通知另一个对象/窗口/程序/等,当您指定的操作发生时,您希望得到通知。例如:系统上的所有窗口都会在他们即将关闭时通知您。

作为一般规则,挂钩有点危险,因为在不了解它如何影响系统的情况下进行挂钩会导致不稳定或出现意外行为。思想认为,它在某些情况下也非常有用。例如:FRAPS使用它来确定它应该显示哪个窗口的FPS计数器。

答案 9 :(得分:1)

一系列钩子是一组函数,其中每个函数都调用下一个函数。一系列钩子的重要意义在于程序员可以在运行时向链中添加另一个函数。一种方法是查找保持链中第一个函数的地址的已知位置。然后保存该函数指针的值,并使用要插入到挂钩链中的函数的地址覆盖初始地址处的值。然后调用该函数,执行其业务并调用链中的下一个函数(除非您另有决定)。当然,还有许多其他方法可以创建一系列钩子,从直接写入内存到使用Ruby或Python等语言的元编程工具。

钩子链的一个例子是MS Windows应用程序处理消息的方式。处理链中的每个函数都处理消息或将消息发送到链中的下一个函数。

答案 10 :(得分:1)

在Drupal内容管理系统中,'hook'具有相对特定的含义。当发生内部事件时(例如,内容创建或用户登录),模块可以通过实现特殊的“钩子”功能来响应事件。例如,这是通过命名约定 - 用户登录事件的[your-plugin-name] _user_login()来完成的。

由于这种约定,底层事件被称为“钩子”,并在Drupal的API文档中以“hook_user_login”和“hook_user_authenticate()”等名称出现。

答案 11 :(得分:1)

非常简短,您可以将API调用的代码(例如MessageBox)更改为它所执行的不同功能(全局将在系统范围内工作,本地将在整个流程中工作)。

答案 12 :(得分:0)

很多答案,但没有例子,所以添加一个虚拟的:下面的 complicated_func 提供了两个钩子来修改其行为

from typing import List, Callable


def complicated_func(
    lst: List[int], hook_modify_element: Callable[[int], int], hook_if_negative=None
) -> int:
    res = sum(hook_modify_element(x) for x in lst)
    if res < 0 and hook_if_negative is not None:
        print("Returning negative hook")
        return hook_if_negative
    return res


def my_hook_func(x: int) -> int:
    return x * 2


if __name__ == "__main__":
    res = complicated_func(
        lst=[1, 2, -10, 4],
        hook_modify_element=my_hook_func,
        hook_if_negative=0,
    )
    print(res)