【问题标题】:What is meant by the term "hook" in programming?编程中的“钩子”一词是什么意思?
【发布时间】:2021-11-12 17:38:01
【问题描述】:

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

【问题讨论】:

  • Hooking @ Wikipedia。该链接隐藏在投票率较低的答案之一中。
  • 事件和钩子看起来很相似。那么有什么区别吗?如果仅在事件发生后调用事件回调(例如click),则有onbeforeunload 事件。这似乎是在实际事件之前调用回调。那么从技术上讲,它是伪装事件的钩子吗?钩子处理程序是在主要操作之前、替代还是之后调用? ...我相信钩子和事件之间有几个区别。钩子看起来像一个低级的干预,一个事件就像一个受限版本的钩子。为什么没有人谈论这个?有人启发我们。
  • @akinuri 你的想法很好,但问题是“钩子”是编程中的“东西”,所以一般来说是一个函数,在某个“事件”发生后调用。事情是一个“事件”可以是另一个函数或另一个回调,由另一个钩子调用,或者是一个浏览器事件,如点击或按键等。所以钩子描述了这个“过程”

标签: hook


【解决方案1】:

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

【讨论】:

  • 这类似于回调吗?
  • 钩子经常(但不总是)使用回调函数。例如,您可以使用“hookEvent(Events.STARTUP, myCallbackFunction)”挂钩事件系统。您将函数指针传递给 hookEvent 函数,因此它知道事件发生时要调用的函数。希望有帮助:-)
  • 完全正确。回调是钩子的“类型”。
  • 嗯...不。回调是回调,与钩子无关,回调只是用于钩子方法的实现。回调是指向函数/方法/过程 (CALL) 的指针 (RELJMP),挂钩是对正在运行的应用程序的修改。
  • @SahilBabbar 否。中断会导致执行某个指定位置(中断)的指令。不过,您可能能够挂钩到中断处理过程,例如通过修改列出中断处理程序位置的表,以便在中断时首先调用您的代码(然后您的代码将调用先前存在的中断处理代码,在菊花链方式)
【解决方案2】:

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

在计算机真正属于个人并且病毒不那么流行的过去(我说的是 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

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

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

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

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

【讨论】:

    【解决方案3】:

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

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

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

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

    【讨论】:

    • “挂钩到页面文档”是什么意思?你能举个例子吗?我理解了第一个例子——给一个 html 元素一个 id,这样你就可以使用 javacript 来修改元素。
    【解决方案4】:

    简单说:

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

    【讨论】:

    • 谢谢。回调函数你也有这么简单的解释吗?
    【解决方案5】:

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

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

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

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

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

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

    【讨论】:

      【解决方案6】:

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

      【讨论】:

        【解决方案7】:

        Hook 表示代码中的一个位置,您在其中调度某种类型的事件,如果该事件之前注册了一个适当的函数来回调,那么它将由这个注册的函数处理,否则什么都不会发生。

        【讨论】:

          【解决方案8】:

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

          【讨论】:

            【解决方案9】:

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

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

            【讨论】:

              【解决方案10】:

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

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

              【讨论】:

                【解决方案11】:

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

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

                【讨论】:

                • 这遵循了above 提到的想法,即“回调”“在发生某事时做出反应”。在这种情况下,回调没有显式注册,而是基于“魔术命名”。目前在 drupal.org 上对此进行了讨论,请参阅 Use Symfony EventDispatcher for event hooks
                • 概括地说,钩子/回调/侦听器可以通过不同的方式“让调用代码知道”(并不是说这是完整的):1. 魔术命名的函数 2. 魔术命名的类3. 显式注册的函数 4. 显式注册的对象(监听器、订阅者、观察者) 5. 显式注册的类名(+ 可选的构造函数参数),在钩子触发之前被实例化。 6.通过修改调用代码
                【解决方案12】:

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

                【讨论】:

                  【解决方案13】:

                  很多答案,但没有示例,因此添加一个虚拟答案:以下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)
                  

                  【讨论】:

                    【解决方案14】:

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

                    【讨论】:

                      猜你喜欢
                      • 2011-01-25
                      • 2013-02-09
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2013-03-14
                      • 2011-04-12
                      • 2018-02-18
                      • 2018-10-29
                      相关资源
                      最近更新 更多