eclipsegc / plugins
这个库提供了一套工具,旨在简化对“类似”对象的发现,将这些对象组装到通用字典中,并简化字典中对象的公共工厂模式。
Requires
- php: >=7.0
Requires (Dev)
- codeclimate/php-test-reporter: dev-master
- phpunit/phpunit: ~5.4
README
什么是插件?
这个库提供了一套工具,旨在
- 简化“类似”对象的发现
- 将这些对象组装到通用字典中
- 简化字典中对象的公共工厂模式
插件库旨在为开发者提供一个简单的模式,允许他们创建自己的可插拔系统。这可以简单到在运行时从库中选择单个插件,或者从库中执行多个插件以执行确定可见性或构建页面组件等操作。
历史与使命
插件系统最初是在2011-2012年与Drupal 8的早期开发一起开发的。尽管Drupal 8于2015年底发布,但插件系统在Drupal 8发布前多年就开始开发,这段代码旨在向整个PHP社区提供插件系统,同时修复Drupal 8版本中许多不完善的地方。我们希望这项工作最终能被整合到Drupal的未来版本中,同时可以在PHP社区中得到更广泛的应用。
用法
每个插件字典必须记录其
- 插件类型
- 发现
- 工厂类
- 工厂解析器
这些属性共同定义了单个插件字典。最容易的入门方法是构建自己的字典类并使用提供的PluginDictionaryTrait。一个简单的例子可能如下所示
use \EclipseGc\Plugin\Dictionary\PluginDictionaryInterface; use \EclipseGc\Plugin\Traits\PluginDictionaryTrait; class MyDictionary implements PluginDictionaryInterface { use PluginDictionaryTrait; public function __construct(\Traversable $namespaces) { $this->discovery = new SomeDiscoveryClass(); $this->factoryResolver = new SomeFactoryResolver(); $this->factoryClass = 'My\Default\Factory'; $this->pluginType = 'myType'; } }
插件类型
插件类型是一个简单的字符串,仅用于文档目的。它允许开发人员询问字典类正在处理哪种插件类型。
理解发现
发现是插件系统最基本的部分之一。构建实现接口的类是很好的,但如果应用程序无法找到和执行它们,那就没有意义。插件系统主要作为一个工具,用于查找“类似”接口的类并将它们提供给执行。它通过以下方式实现
- 公开和记录用于交换子系统内的类
- 提供一种或多种模式,通过这些模式可以在子系统中逻辑上找到打算使用的类。
- 提供实例化这些类的方法。
此过程中最关键的部分是用于逻辑上定位相同接口的类的模式。整个系统完全是可插拔的,但为了简单起见,您可以认为发现是任何中央工具可以找到的文档,并从中加载其中一个已记录的类。例如,您可以想象一个神奇的PHP可调用对象,它返回一个插件定义数组或YAML,这些可以解释为插件定义。一种这样的发现解决方案已经存在,它利用了Doctrine的类 注释。
发现(Discovery)旨在为开发者提供一个自文档化的机制,以便在整个可用的命名空间中查找新的插件。使用上面的注释示例,要被找到,新的插件必须存在于预期的目录结构中,实现特定的接口,并带有预期的注解类。你可以在其GitHub页面上了解更多关于该特定发现机制的信息。
要执行此类发现调用,插件系统需要每个命名空间及其对应的目录。对于基于Composer的自动加载,插件系统提供了一个静态方法,可以执行必要的操作。只需将自动加载器传递给Namespaces::extractNamespaces()方法。上面的代码文档中看到的可遍历(Traversable)对象就是结果。
工厂类
在插件字典中记录的工厂类是一个回退工厂,用于实例化任何插件。这意味着插件类型的最基本期望应该封装在默认工厂类的期望中。
工厂解析器
工厂解析器的任务是按需实例化工厂类(包括默认工厂)。由于每个插件在实例化时可能有根本不同的需求,因此解析器允许插件单独记录自己的工厂,以便在实例化时有特殊需求。
工厂解析器旨在减少依赖注入问题。允许单次使用的工厂类与单个插件配对,可以防止插件类与一组依赖项紧密耦合。所使用的工厂类带有注解,注解可以在运行时或缓存之前更改。静态工厂方法(Drupal 8用于解决此类基本问题的机制)不能。
如果你正在使用依赖注入容器或类似的控制反转机制,那么你的工厂解析器可能会成为那里的服务,并将整个容器传递给它。这使它们能够在实例化其工厂时满足任何插件的依赖项。在Drupal 8的术语中,这个插件系统实际上将静态工厂方法从插件类本身移动出去,并允许在定制的工厂类上发生相同的代码流,以防止将插件紧密耦合到服务中。