noccylabs / pluggable
应用程序的插件管理器
Requires
- symfony/event-dispatcher: ~2.4
- symfony/finder: ~2.4
- symfony/yaml: ~2.4
Requires (Dev)
- noccylabs/virtfs: 0.1.*
- psr/log: ~1
- symfony/dependency-injection: ~2.4
Suggests
- noccylabs/virtfs: to load plugins from zip files and more
README
注意:此README适用于Pluggable的0.2.x分支
Pluggable是一个PHP插件管理器。它提供了一个裸露的可控框架,可以从文件系统或甚至从.zip或.phar文件按需加载和卸载代码占位符。
安装
$ composer require noccylabs/pluggable:0.2.x-dev
使用
创建一个NoccyLabs\Pluggable\Manager\PluginManager实例,并添加您希望从中加载插件的后端
// Find and load all plugins from virtual filesystem $vfs
$plug = new PluginManager();
$plug
->addBackend(new VirtFsBackend($vfs, null))
->findPlugins(true)
;
后端
您可以添加多个后端。它们的添加顺序是相关的,如果插件在多个位置找到。例如,想象以下场景:
- 插件
plugin.foo随fooapp.phar一起提供,并使用StaticBackend加载。 - 文件
~/.fooapp/plugins/plugin.foo.zip也包含plugin.foo,并通过VirtFsBackend加载。
当加载插件plugin.foo时,它将从VirtFs后端加载,因为它是在最后遇到的。这允许您包含可以外部升级的静态插件。
$plug
->addBackend(new StaticBackend(..))
->addBackend(new VirtFsBackend(..))
DirectoryBackend
Directorybackend从一组目录加载插件。此后端只能直接从源加载,而不能通过phar、zip或其他存档。
new DirectoryBackend(array(
"/foo/bar",
"/foo/biz",
"/var/bar"
));
VirtFsBackend
VirtFsBackend从由映射目录和zip文件组成的VirtFs文件系统加载插件。要使VirtFs后端工作,必须将协议分配给VirtFs对象(默认名称"plugins"),以允许通过virtfs包装器访问插件。
new VirtFsBackend($vfs, "/");
StaticBackend
StaticBackend返回静态预初始化插件的列表。对于嵌入插件,例如在创建phar可执行文件时使用。
new StaticBackend(array(
"my.plugin.id.one" => 'My\Plugin\Class',
"my.plugin.id.two" => 'My\Other\Plugin\Class'
));
查找插件
将true传递给PluginManager#findPlugins()将加载后端找到的所有插件
$plug->findPlugins(true);
上面的功能与以下相同
$plug->findPlugins( function ($plugin) {
return true;
});
要选择要加载的插件,可以这样做
// Read plugins loaded since last time
$plugins_to_load = file("plugins.lst", FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
// Use a custom callback to see if the plugin is in the list
$plug->findPlugins( function ($plugin) use ($plugins_to_load) {
$plugin_id = $plugin->getPluginId();
return in_array($plugin_id, $plugins_to_load);
});
// Write the list back out
$loaded_plugins = $plug->getLoadedPluginIds();
file_put_contents("plugins.lst", join("\n", $loaded_plugins));
编写插件
插件应实现NoccyLabs\Pluggable\Plugin\PluginInterface或扩展NoccyLabs\Pluggable\Plugin\Plugin。如果您选择使用接口,您有责任响应PluginInterface#onActivate()以及PluginInterface#isActivated()以反映状态。如果您扩展插件,您可以代替覆盖Plugin#load()方法,将齿轮和扳手留给Pluggable。
插件需要在支持的任何语言中具有清单(除非使用StaticBackend加载),例如json、yaml或sdl。请注意,yaml和sdl可能需要安装额外的库才能进行解析。
| Language | Filename | Requirements |
|===========|==========================|=============================|
| Json | `plugin.json` | php5-json |
| Yaml | `plugin.yml` | php5-yaml or symfony/yaml |
| Ini | `plugin.ini` | |
文件应定义以下值
- id - 插件id,例如foovendor.myplugin
- ns - 插件根目录的命名空间(psr-4)
- class - 从指定ns加载的类
- name - 插件名称
接口
通过调用PluginManager#addInterfaceLoader(),可以为实现特定接口或扩展特定类的插件创建回调。内部使用instanceof来比较实例与请求的名称。
class MyPlugin extends Plugin implements ICanAddInterface
{ ... }
$plug->addInterfaceLoader("ICanAddInterface", function ($plugin) {
$sum = $plugin->addNumbers(5, 4);
});
或用于设置容器等
$plug->addInterfaceLoader($container_interface, function ($plugin) use ($container) {
$plugin->setContainer($container);
});
通用加载器
还提供了通用加载器
$plug->addLoader(function ($plugin) {
// ...
});