326

我最近在与一些人谈论我正在编写的程序时听到了“钩子”这个词。尽管我从对话中推断出钩子是一种函数,但我不确定这个术语究竟意味着什么。我搜索了一个定义,但找不到一个好的答案。有人能给我一个关于这个术语的一般含义的想法,也许还有一个小例子来说明这个定义吗?

4

14 回答 14

184

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

于 2009-01-21T23:55:28.270 回答
96

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

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

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

例如,这些行:

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

将列出磁盘内容然后重新初始化机器。这允许通过将第一行设置为来保护您的 BASIC 程序等技巧:

123 REM XIN#6

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

这通常是我们不得不求助的那种诡计,以获得我们想要的行为。

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

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

于 2009-01-22T00:12:25.007 回答
58

在一般意义上,“钩子”是让您(程序员)查看和/或与之交互和/或更改系统/程序中已经发生的事情的东西。

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

回调可以被认为是一种特定的钩子。通过在系统中实现回调功能,该系统允许您在操作完成后调用一些额外的代码。然而,钩子(作为一个通用术语)并不局限于回调。

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

于 2009-01-22T00:18:18.410 回答
40

简单说道:

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

于 2016-08-02T14:36:17.083 回答
26

Hooks 是一类函数,允许基本代码调用扩展代码。这在核心开发人员想要提供可扩展性而不暴露其代码的情况下很有用。

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

一个常见的实现方法是给一个函数一个空的回调列表,然后公开扩展回调列表的能力。基本代码将始终在相同和适当的时间调用该函数,但是,对于一个空的回调列表,该函数什么也不做。这是设计使然。

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

钩子不允许开发人员做任何其他结构和接口无法完成的事情。它们是在考虑任务和用户(第三方开发人员)的情况下做出的选择。

为了澄清:钩子允许扩展并且可以使用回调来实现。回调一般无非就是一个函数指针;函数的计算地址。其他答案/评论似乎存在混淆。

于 2016-01-25T15:57:42.383 回答
19

编程中的挂钩是一种使用所谓的挂钩来制作一系列过程作为事件处理程序的技术。

于 2009-01-21T23:58:52.507 回答
5

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

于 2014-04-05T05:05:27.387 回答
2

遇到某些条件时可以执行钩子。例如,某些变量更改或某些操作被调用或某些事件发生。钩子可以进入过程并改变事物或对改变做出反应。

于 2009-01-22T00:00:41.877 回答
1

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

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

于 2009-01-22T00:05:53.850 回答
1

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

挂钩链的一个示例是 MS Windows 应用程序处理消息的方式。处理链中的每个函数要么处理一条消息,要么将其发送到链中的下一个函数。

于 2009-01-22T00:24:51.470 回答
1

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

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

于 2009-01-22T00:35:15.833 回答
1

简而言之,您可以更改 API 调用的代码,例如MessageBox它执行您编辑的不同功能的位置(全局将在系统范围内工作,在本地将在进程范围内工作)。

于 2012-08-18T07:39:23.053 回答
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)
于 2021-05-28T09:59:19.740 回答
0

一个函数,它允许您提供另一个函数,而不仅仅是一个值作为参数,本质上是扩展它。

于 2021-11-12T09:38:01.313 回答