【问题标题】:A php plugin architecture一个php插件架构
【发布时间】:2023-04-03 02:45:01
【问题描述】:

我正在想办法为我自己的框架创建一个插件架构。我已经阅读了许多主题并在这里和其他网站上发帖。基本上我已经找到了以下解决方案,这似乎是 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(以及其他一些框架)。

【问题讨论】:

    标签: php plugins architecture


    【解决方案1】:

    更新:答案现在反映了最新的链接和更好的描述。

    当然有很多不同的方式来设计一个插件系统,也许在https://softwareengineering.stackexchange.com/ 上提问会给你更多的想法,但我会尝试通过分享我的想法和经验来提供帮助。

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

    挂钩

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

    在重构我的框架时,我将钩子实现分离为一个单独的特征并在此处记录: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} 标签中,该标签在 Layout 的 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

    用户界面/数据分离

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

    虽然许多 UI 生成器需要开发人员手动构建它们并与数据链接,但我正在注入这样的“模型”对象:

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

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

    在这种方法中,对象User 包含足够的元数据,以便表单填充其字段、标题执行验证以及保存/加载数据。

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

    其他方法

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

    工厂:

    将指定为字符串的类解析为命名空间/文件的能力:

    $api->add('MyClass');
    

    使插件能够重新路由标准类,但对 IDE 中的类型提示不太友好。

    新类型/特性:

    插件可以提供新的类添加持久性、表格列、表单字段、操作等。

    结论

    我认为附加设计归结为:

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-19
      • 2014-04-28
      • 2011-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多