编程中的“挂钩”是什么意思?


248

我最近在与某些人谈论我正在编写的程序时听到了“挂钩”一词。尽管我从对话中推断出挂钩是一种函数,但我不确定该术语的确切含义。我搜索了一个定义,但找不到一个好的答案。有人可以让我了解这个术语的一般含义,也许还可以举一个小例子来说明这个定义?


3
参见Hooking @ Wikipedia。该链接埋在投票率较低的答案之一中。
Palec 2014年

Answers:


143

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


7
这类似于回调吗?
克里斯,2009年

19
挂钩经常(但不总是)使用回调函数。例如,您可以使用“ hookEvent(Events.STARTUP,myCallbackFunction)”来挂钩事件系统。您正在将函数指针传递给hookEvent函数,因此它知道事件发生时要调用的函数。希望能对您有所帮助:-)
威廉·布伦德尔

6
究竟。回调是钩子的“类型”。
米卡

21
不。回调是一个回调,与钩子无关,回调函数仅用于实现钩子方法。回调是指向函数/方法/过程(CALL)的指针(RELJMP),挂钩是对正在运行的应用程序的修改。
specializt

1
@SahilBabbar编号。中断会导致在某个指定位置(中断)执行指令。但是,您可能可以进入中断处理过程,例如,通过修改列出中断处理程序位置的表,以便在中断时首先调用您的代码(然后您的代码将调用以前存在的中断处理代码,菊花链方式)
David Tonhofer 2016年

77

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

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

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

为了获得我们想要的行为,这通常是我们必须采取的手段。

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

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


41

从广义上讲,“钩子”是一种使您(程序员)能够查看和/或与之交互和/或更改系统/程序中已在进行的事物的事物。

例如,Drupal CMS为开发人员提供了挂钩,让他们在创建“内容节点”之后采取其他措施。如果开发人员未实现挂钩,则按常规创建节点。如果开发人员实现了挂钩,则每当创建节点时,他们都可以运行一些其他代码。该代码可以执行任何操作,包括回滚和/或更改原始操作。它也可以做一些与节点创建完全无关的事情。

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

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


“挂入页面文档”是什么意思?你能举个例子吗?我理解了第一个示例-给html元素一个id,以便您可以使用javacript修改该元素。
committedandroider

21

简单地说:

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


最佳答案imo
Daniel

15

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


15

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

挂钩的一种用法是在视频游戏模块开发中。游戏可能不允许mod开发人员扩展基本功能,但是核心mod库开发人员可以添加挂钩。使用这些挂钩,独立开发人员可以在任何所需事件(例如游戏加载,清单更新,实体交互等)下调用其自定义代码。

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

这样,第三方就有机会编写其他代码并将其新的回调添加到挂钩的回调列表中。除了参考可用的挂钩以外,它们还具有扩展功能,对基本系统的风险最小。

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

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


4

挂钩表示代码中您分派某种类型的事件的位置,如果该事件之前已使用适当的函数注册以进行回调,则该事件将由此注册函数处理,否则不会发生。


2

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


1

挂接通常是指Win32消息挂接或Linux / OSX等效项,但是更笼统地说,挂接只是在发生指定的操作时通知另一个对象/窗口/程序/等您想通知的对象。例如:在系统上所有窗口即将关闭时会通知您。

通常,挂接有些危险,因为在不了解挂接方式如何影响系统的情况下进行挂接可能会导致不稳定或非常意外的行为。考虑到在某些情况下它也可能非常有用。例如:FRAPS使用它来确定应该在哪个窗口上显示FPS计数器。


1

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

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


1

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

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


这遵循了上面提到的“回调”“在事情发生时做出反应” 的想法。在这种情况下,回调未显式注册,而是基于“魔术命名”。当前在drupal.org上对此进行了讨论,请参阅使用Symfony EventDispatcher进行事件挂钩
donquixote 2012年

概括地说,可以通过不同的方式(不是说这是完整的)“使调用代码知道钩子/回调/侦听器”:1.以魔术命名的函数2.以魔术命名的类3.显式注册的函数4.显式注册对象(侦听器,订户,观察者)5.显式注册的类名(+可选的构造函数args),要在钩子触发前实例化。6.通过修改调用代码
donquixote 2012年

1

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.