一个php插件架构

时间:2012-04-07 09:59:42

标签: php plugins architecture

我正在尝试为自己的框架创建插件架构的方法。我已经阅读了很多主题,并在这里和其他网站发布。基本上我已经找到了以下解决方案,这似乎是PHP(目前)唯一的好选择。

这个想法是每个类都像类一样扩展了一种观察者。所以Template类,BaseController等总是扩展一个Plugin类。

class BaseController extends Plugin
{
    public function __construct()
    {
        // Plugin check, notify all loaded plugins
        $this->checkForEarlyHooks();

        // Init some standard stuff
        $this->view = new Template();
        $this->baseLayout = 'layout.html';

        $this->something = new Something();

        // Plugin check, notify all loaded plugins
        $this->checkForLateHooks();
    }
}

所以这里基本上发生的是当indexController扩展baseController时,插件检查就完成了。在这种情况下为构造函数。在实际调用Action方法之前,当您想要使用插件进行某种登录检查时,这很方便。

Plugin类可以解析从哪个类调用,并知道在加载的插件中要查找的函数。

另请注意,它会检查已加载的插件列表2次。在构造函数中加载(早期)之前的一个,并且在加载所有变量(晚期)时加载一个。

我还可以在“checkForLateHooks()”函数中添加变量。所以钩子函数也可以操作它们,比如'baseLayout'变量。

钩子函数看起来像这样:

public function hookConstruct ( &$baseLayout )
{
    $baseLayout = 'login.html';
}

现在基本上我的问题是,这种做法有什么好处吗?我知道也有很多其他方法可以做到这一点。但我主要不想在以后遇到设计问题。现在看来这是一个好主意,但你永远不知道事情会如何发挥作用......

如果我记得正确(从我读过的所有帖子中),这有点像WordPress(以及其他一些框架)。

2 个答案:

答案 0 :(得分:6)

更新:现在,answer会反映最新的链接和更好的说明。

设计插件系统肯定有很多不同的方法,也许在https://softwareengineering.stackexchange.com/上询问会给你更多的想法,但我会尝试分享我的想法和经验。

我将分享一些我自己通过一系列自己的框架学到的经验。目前Agile UIAgile Data都支持扩展,但我会专注于“组件”

当你想要将代码注入现有对象时,钩子是一种标准的方法。这是使用已建立的结构扩展应用程序或流程的最佳选择。

在重构我的框架时,我将钩子实现分离为一个单独的特征并在此处记录:http://agile-core.readthedocs.io/en/develop/hook.html

主持人申请:

... some code here ..
$this->hook('beforeInit');
$this->init();
$this->hook('afterInit');
... code goes on ..

插件:

$host_app->addHook('beforeInit', function($object) {
    echo "About to execute init of $object";
});

UI组件

组件呈现不同的设计模式,适用于用户界面。您可以从页面/应用程序布局开始,然后将其分解为菜单,页眉,页脚,内容。

组件是可以与布局或其他组件关联的对象。每个组件都能够呈现并将额外的HTML / JS传递给其父组件。大多数组件也是一个交互对象。

这种方法称为“渲染树”,应用程序执行分为两个阶段 - “初始化渲染树”,然后“渲染”。

主机申请:

$layout->menu = new \atk4\ui\Menu();
$layout->add($layout->menu, 'TopMenu');

上面的代码显示了如何初始化新组件(菜单)并将其插入$layou。此外,$ menu的HTML输出被定向到{$ TopMenu}标签,该标签在布局的HTML模板中定义。

插件可以通过以下方式与渲染树交互:

  • 在树中的任何位置添加更多组件
  • 影响现有组件(例如添加新菜单项)
  • 销毁任何现有组件

当这些方法结合起来时,您可以使用以下内容:

$app->addHook('afterInitLayout', function($app) {

    $app->layout->menu->destroy(); // remove default menu
    $app->layout->menu = new \plugin\SuperMenu();
    $app->layout->add($app->layout->menu);
});

这可用于通过附加组件中更强大的实现替换标准菜单。

此处记录了我的组件实现:

http://agile-ui.readthedocs.io/en/latest/view.html#initializing-render-tree

UI /数据分离

虽然对于一个问题可能没有那么多答案,但另一个有效的扩展方式是分离关注点。 Agile UI中的所有UI组件都不知道如何对数据执行任何操作。

虽然许多UI生成器要求开发人员手动构建它们并与数据链接,但我正在注入“Model”对象,如下所示:

$form->setModel(new User($db)); // populates name, surname and gender fields

演示:http://ui.agiletoolkit.org/demos/form2.php(第二种形式)

在此方法中,对象User包含足够的元数据,用于填充表单的字段,字幕执行验证以及保存/加载数据。

由于“User”类也可以在附加组件中声明,因此通过添加对新数据实体的支持,它是扩展现有功能的一种非常强大的方法。

其他方法

使用附加组件扩展的其他一些方法包括:

厂:

将指定为字符串的类解析为namespace / file的能力:

$api->add('MyClass');

为附加组件提供重新路由标准类的能力,但对IDE中的类型提示不是很友好。

新类型/特征:

加载项可以提供添加持久性,表格列,表单字段,操作等的新类。

结论

我认为附加设计归结为:

  • 安装和使用的简单性
  • 附加组件是否需要开箱即用?
  • 避免加载项之间的冲突
  • 定义不同的附加组件类型 - 身份验证,UI,行为
  • 可以附加扩展另一个附加组件
  • 将增加适合的应用程序设计,数据和架构吗?
  • 在不牺牲性能的情况下为附加组件提供大量功能

答案 1 :(得分:1)

https://github.com/gheevel/PHPPlugin上查看PHPPlugin。一个简单的PHP插件框架,受eclipse和jira插件架构的启发。基本上,您的应用程序可以定义扩展点,插件实例可以在这些扩展点上注册以提供额外的功能。与作曲家和/或symfony结合使用效果很好。