namelesscoder / event-engine
This package is auto-updated.
Last update: 2024-09-12 04:13:35 UTC
README
目的:提供一组干净且严格的接口和围绕“事件”概念(即在您的代码中发生的事情,其他代码可以监听并对其做出反应)的稳健默认实现。
事件、钩子、信号——正如我们在丹麦所说,一个亲爱的孩子有许多名字。这个事件包的概念源于TYPO3 CMS长期而辉煌的历史,并从其他基于事件的实现中汲取灵感。它旨在允许一组关键功能
- 显然,分发事件。
- 能够将事件配对,例如,“开始”和“停止”事件对,以执行特定操作。
- 能够从您的应用程序内部报告数据(有效负载)给需要它的第三方代码。
- 如果需要,允许第三方代码修改事件的数据,并在应用程序的后续操作中使用修改后的数据。
- 使一个处理程序能够处理几种类型的事件,并使处理程序负责报告它将监听哪些事件类型(从而允许在实现中动态决定)。
这些部分共同构成了一个灵活且相当强大的框架,使实现应用程序中的事件变得容易——并可作为第三方与您的应用程序进行集成的通用API使用。
它是如何工作的
我建议您快速查看examples
文件夹中的示例应用程序。这个小程序使用了EventEngine的所有基本部分,并使用代码中的注释进行了彻底的文档说明。
示例应用程序是可执行的——您可以在命令行中运行它,或者使用httpd提供服务。然而,它却是完全非交互式的;它从任何地方绝对不接受输入参数。
关于时间跟踪功能的说明
虽然可以说使用事件跟踪时间并不完全属于事件库的范畴,但在这一低级别添加它具有显著的优势。首先,时间跟踪的成本极低。其次,基于事件的仪器的一个常见用例涉及跟踪事件之间的时间——无论是用于性能分析、记录“慢操作”还是其他类似情况。
因此,此库中包含了一些方法和“配对事件”的概念来实现时间跟踪。
关于配对事件的说明
这个概念基本上直接来源于TYPO3 CMS中几个“之前”和“之后”样式的钩子。简单来说,有些钩子需要在动作发生之前触发——其他钩子需要在动作之后触发。然后,每个钩子接收不同的数据,例如,“之后”钩子接收应用程序在“之前”钩子和该钩子之间创建的内容。
没有声明规则来命名哪个钩子是“之前”或“之后”钩子——这完全由事件是否有“触发事件”(它本身也是一个事件)来决定。
这意味着,当事件有“触发事件”并且这两个事件都有创建时间戳时,可以很容易地计算出触发事件和配对事件之间的持续时间。而且,因为事件调度器返回它已分发的事件,这使得实现这种类型的“之前”和“之后”配对事件变得非常容易。考虑以下示例
$startEvent = $eventDispather->dispatch( new Event( MyEventType::cast(MyEventType::MY_EVENT), new EventData(['foo' => 'bar']) ) ); // Application now does something that takes a bit of time $endEvent = $eventDispatcher->dispatch( new Event( MyEventType::cast(MyEventType::MY_EVENT_FINISHED), new EventData(['foo' => 'bar']), $startEvent ) ); // Meanwhile, every handler that is capable of handling the // "finish" Event will have received an Event which has a duration. // EventHandlers may read this duration - but so may your application: $logger->doLogging('Doing action XYZ took ' . number_format($endEvent->getDuration(), 3) . ' milliseconds');
通过分发之前和之后的事件,您就获得了三个功能
- 让第三方监听事件并处理它们的明显好处,以及如果他们需要的话,跟踪时间。
- 您的应用程序还可以读取第一对和第二对事件之间的持续时间,这是它的次要优势。
- 第三级优势是,EventHandler可以使用一种类型的事件,通过简单地通过第二对事件访问启动事件的数据,来比较前后事件中的数据。
实际上,只需两次调用microtime(true)
和一次减法计算就可以跟踪所有这些,这就是为什么它是库本身的一部分的原因。
它不做什么?
该包在设计时考虑了KISS和YAGNI原则(保持简单,傻瓜 - 以及您不需要它),这意味着它没有优先级、基于依赖的处理程序排序、各种事件特殊实现和内置事件类型等花哨的功能。该包没有这些功能。
它所拥有的是足够灵活的基础库,允许您使用任何数量的特殊功能来创建所有这些功能的自定义实现。
简而言之,这个包主要存在是为了提供接口;所有与事件相关的事物的合同,仅限于事件。它确实提供了接口的通用实现,但它们故意保持在绝对最小复杂性,只具备足够的能力来履行合同。
重要
- 该包不包括默认的EventHandler - 以及一个事件类型(枚举对象),这两个组件您必须为您的应用程序构建,或者找到您可以使用单独包的情况。
- 该包声明了零个事件类型,除非您声明这些或添加一个包含这些的事件类型的包,否则将没有要发送的内容。
(非常)简短的历史
“事件”的概念既不是突破性的,也不是TYPO3 CMS独有的。事实上,它现在已经是一个行业标准,从JavaScript世界广为人知,由来已久。
但为了解释为什么EventEngine包这样做,有必要简要回顾TYPO3 CMS在第三方代码集成方面的历史。
- 第一个迭代版的“用户函数”可以配置在各种情况下调用,例如返回简单的字符串值用于HTML输出,这几乎是随着TYPO3的第一个版本一起出现的。尽管这些方法在它们明确和易于定义方面很好,但它们缺乏灵活性,因为一次只能配置一个。
- 然后出现了“钩子”,几乎不言自明:而不是声明一个函数,现在可以声明一个函数引用数组,当系统发生某些操作时,这些函数会按顺序调用。这个概念使得第三方代码能够改变TYPO3 CMS在应用程序后续过程中使用的数据 - 例如,允许在预览时动态更改内容元素的标题。
- 后来出现了“信号”的概念,最初是作为PHP框架Flow的一个回滚版本,现在是Neos。尽管TYPO3 CMS已经有了“钩子”的概念,但Flow/Neos需要一个更严格的实现,并创建了“信号”,与更基本的函数引用数组相反,它可以通过引用发送它们的类和信号名称来订阅信号。
今天,这三个概念仍然存在于TYPO3 CMS中,不难论证应该将它们统一到一个单一实现中,该实现服务于所有非常相似的目的。然而,由于对“用户函数”的极度内建支持,这在TYPO3 CMS中用于TypoScript的几乎所有方面,EventEngine并不打算取代这种模式 - 尽管它可以与它一起使用,以取代当前“用户函数”,并将它们转换为分发的事件,允许第三方接收、修改并将数据传回TYPO3。