shift8/intercept

一个小型软件包,帮助您编写更周到的PHP代码。

0.1.0 2015-08-07 15:56 UTC

This package is not auto-updated.

Last update: 2024-09-18 19:16:50 UTC


README

提供可扩展的基础类,允许您轻松构建具有可过滤方法(拦截器模式)的类。这是一个小型(约1,100行代码,包括许多注释)库,易于使用,并为您的库提供大量灵活性。

这既不是框架,甚至也不是一个微型框架。它仅仅是一个起点。您可以从这里构建一个框架,但我建议您在那个阶段查看Lithium(li3),因为很多内容都来源于那里。

使用这些基础类将使用户(以及您自己)的代码维护量减少,以及当API更改时减少破坏性变更。它还有助于关注点的分离。

目标

简单来说,这个库(或类集合的样板)有两个主要目标。

  1. 提供配置约定
  2. 允许方法可过滤

配置约定

您会注意到StaticObjectObject类的构造函数都接受一个选项数组。这种约定消除了位置参数的问题,如果您采用它,将减少未来的破坏性变更和代码维护。一些聪明的人称之为统一构造函数。

当然,您完全可以偏离这个约定。您不需要接受它。也许您想引入一个依赖注入库...无论怎样,都可以。

然而,对于简单的库来说,整个DI系统可能过于庞大。因此,这个简单的配置约定为您提供了一个很好的指导。它是微妙的,但很重要。

记住,位置参数是走向黑暗面的途径。构造函数中的位置参数会导致API更改。API更改会导致破坏性变更。破坏性变更会导致痛苦。

可过滤方法

TL;DR?
简而言之,使用这种方法,与使用其他方法相比,将为您和您的库用户节省大量时间和头疼的问题。

当前的问题及一些其他解决方案

如果您想编写其他人使用的PHP类(开源或否则),那么您需要意识到,有人可能不同意您做事的方式,或者只是想以不同的方式做事。这可能是一个非常小的调整。

然而,这就是球开始散乱的地方。这就是我们陷入维护地狱的地方。这就是版本控制变得重要的地方,破坏性变更可以轻易地引入到项目中。

有一些方法可以让一些类和方法以更灵活的方式与最终用户一起工作。

1. 扩展类

可能最简单的方法是扩展它。如果您想改变某些东西,这是面向对象编程...去做吧。当然,这行得通...但这是最容易在原始作者更新他们的库并且最终用户想要获取这些更新时遇到破坏性变更的方式。

这也会带来很多额外的工作。现在您需要创建一个新的类并扩展其他类,可能还需要从该库中引入其他类,这取决于复杂性,只是为了可能的小调整。

如果您要扩展类,请扩展这里的类。

2. 插件

这些在许多PHP框架和库中很常见。例如,如果您熟悉CakePHP,您一定会知道beforeFilter()afterFilter()。这类插件的问题在于它们在代码库的固定点被调用。您没有太多的灵活性。

Drupal的用户可能非常熟悉“钩子”这个术语,因为它们无处不在,而且在CMS中也有点不同于CakePHP。实际上,如果你简单地将Drupal中所有可用的钩子列出来,你会很快意识到这可能会成为一个完全的维护噩梦。

3. 事件调度器

事件与钩子非常相似,只是可以更多。它并不完全受限,但当这些事件被调度时,仍然受限。当然,你还需要编写处理这些事件的函数。所以还有更多的代码要编写和维护。

Symfony框架有一个事件调度器系统。如果你看看那个文档,你会看到那里涉及到多少额外的工作。

关注点分离

这一点很重要。上述所有方法,除了可能的事件调度器,都会让你有点不知道需要在哪个地方编写代码。所以,如果你需要执行其他任务,从组织或架构的角度来看最好保持独立(比如,日志记录),你就无法做到。

使用拦截过滤器模式,你可以做到。原始方法不会知道你的日志类或方法调用。这些调用甚至不需要从该方法或甚至在同一个PHP文件中调用。

这有助于维护、测试、架构、组织和团队合作!是的,如果你不经常在同一个文件上争斗,你可以更轻松地与他人合作。尽管我们有修订控制、分支和合并,但以有序和隔离的方式工作仍然很好(我不是说不要合作或互相交谈,我只是说你们有时会互相干扰,这可以缓解这种情况)。

更好的方法:拦截过滤器

上述方法的替代方案是这些核心类中提供的过滤器系统。这两个类是你自己需要的唯一两个类。当你编写方法时,你现在可以以可过滤的方式编写它们。

这允许其他人应用任意数量的闭包,这些闭包在链中运行。它们传递所有参数,并能够改变方法的行为。不仅仅是它在完成之后或发生之前做某事。

这是一个更灵活的解决方案,并为你提供了更大的控制权。

它还实现了关注点分离,因为最终用户可以从代码库的任何地方应用这些过滤器,当然,前提是在调用方法之前。

这个库提供了允许你以相当稳健的方式处理此链的方法。你可以给每个过滤器分配一个名称。你可以按任何顺序应用过滤器。你可以删除过滤器或替换它们。

所以,如果你编写了一些使用这个库的代码,然后有人编写了一些使用你的库的代码,然后有人使用那段代码……每个人在路上的都可以修改你的原始代码的行为!

困惑吗?是的!解释起来有点困难,但这里的思想是减少分叉和减少“修改核心”这样的说法。你只需要在实践中看到它,别担心,我们有示例。

使用示例

好了,现在这个神奇的模式听起来不错。它不同,它以巧妙的方式使用闭包来完成,你可能想知道它是如何工作的。

学习最佳方式可能是查看库中包含的示例。在您的类扩展了\Shift8\Intercept\Object\Shift8\Intercept\StaticObject类之后,允许您的函数可过滤的魔法部分将是

return $this->_filter(__METHOD__, $params, function($self, $params) {
	// Whatever you want to do, do it here and return the result.
	return 'test result';
});

基本上,您返回一个闭包,并在其中放置所有代码。在这里,$params将是一个数组,您希望将其传递到链中。它们来自您的方法所接受的参数。您可以使用PHP的compact()函数来帮助您。然后在闭包内部,您可以自由地使用extract()或直接在键数组中引用参数。

在编写自己的方法时,您基本上只需记住这一点。

静态方法的工作方式几乎相同。

$params = compact('options');
return static::_filter(__FUNCTION__, $params, function($self, $params) {
	// Whatever you want to do, do it here and return the result.
	return 'test static result';
});

然后,您和任何使用您的类的人都可以过滤您暴露的可过滤方法。

缺点

是的,有一些缺点。在编程中总是如此,这里也不例外。您会注意到最大的问题是调试代码变得有点困难。现在您位于这些闭包中。代码自动完成在这里也可能有点困难。

这里的一个经验法则是,如果对方法的修改变得过于复杂(这里必须使用判断),那么最终用户可能最好是从库中分叉或扩展其中的类。当然,这个库不可能适应所有场景,但无疑是一个良好的起点。

另一个缺点(这也适用于事件处理方法)是,由于您有更多的灵活性,您需要在放置代码的地方保持组织。您几乎可以从任何地方应用过滤器,但这并不意味着您应该从任何地方应用它们。保持代码的组织。这是库作者和最终用户的责任。