V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xiaotuzi
V2EX  ›  PHP

有个 PHP 插件设计思路想跟大家探讨下是否可行?

  •  
  •   xiaotuzi · 2019-09-04 17:08:39 +08:00 · 4153 次点击
    这是一个创建于 1907 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我自己开发了一个 MVC 架构的 CMS 系统(以前帖子提过,暂时只开发到 dev 版本,beta 还未发布),目前系统有个插件功能,我原本已有的一个设计思路是这样:

    ①系统入口-->根据路由检测 controller 及 action,优先调用插件 plugins 目录的 controller 和 action 如下:

    url:http://xxxx/Index/index

    ↓↓访问插件目录( plugins )同名控制器 IndexController.php 里面的 index 方法

    Home/plugins/IndexController.php

    ↓↓如果不存在同名控制器或者存在控制器,不存在对应方法 index,则访问系统控制器

    Home/IndexController.php

    上面这个是已有的插件设计思路,用户只需要制作同名控制器放入 plugins 文件夹即可,但是有个弊端是一个方法只能设计一个插件,因为不能存在多个同名文件共存的情况。所以,我打算重新增加一个插件设计,如下:

    ②系统入口-->根据路由检测系统模块 Home、controller 及 action,查询对应 hook 表内是否有注册这个控制器的插件(钩子),如下:

    url:http://xxxx/Index/index

    ↓↓根据模块 Home、控制器 Index、方法 index 查询表 hook 是否有注册对应的钩子,如果有,则预选执行钩子,如:TestController.php 里面的 index 方法绑定了这个方法,存在多个则根据排序 orders,依次执行。

    Home/plugins/TestController.php Class(Test)->index() 如果存在多个注册:

    ( Home/plugins/Test1Controller.php Class(Test1)->index1())

    ( Home/plugins/Test2Controller.php Class(Test2)->index2())

    ↓↓执行完 hook 表里注册的钩子,再执行真正的控制器,当然,有可能钩子里面就直接 exit 了,不再执行下去。

    Home/IndexController.php Class(Index)->index()

    如上,两种设计思路,可能都是我自创的,我希望是所有控制器都能够自由定义,不拘于个别放置埋点的地方才可以设计插件。第一种设计,在不改动系统文件情况下,完美融入系统,弊端前面也说了,一个类里面的同个方法不能接入多个插件。第二种是我今天刚设计出来的,在安装插件的时候,需要在 hook 表里面新增注册的插件,一个方法可以不限制注册插件个数,执行顺序也可以自由定义,我感觉每次查询数据库这个会导致很大的问题,如果 100W 访问,估计数据库直接 GG 了,要不改为读取文件的形式?实际运用不知道会出现什么状况?想问问大家有什么弊端?或者推荐一下你自己的设计思路,友善谈论。

    第 1 条附言  ·  2019-09-06 06:57:50 +08:00
    已找到解决方案:
    缓存 Hook 表,每次访问 foreach 查询对应匹配的插件,如果有则依次执行,同时保留第一种设计方案,如果觉得实例化多个插件会导致内存消耗大,运行速度慢,可以使用第一种设计思路将几个同方法的注册插件整理下写到一个方法内,就不需要实例化多个了。
    11 条回复    2019-09-10 16:27:20 +08:00
    yinjy
        1
    yinjy  
       2019-09-04 17:23:26 +08:00
    没看明白,感觉像中间件?
    ben1024
        2
    ben1024  
       2019-09-04 17:26:32 +08:00
    可以注册时进行代码验证,注册后加入缓存
    tmkook
        3
    tmkook  
       2019-09-04 17:38:33 +08:00
    不要考虑数据库查询次数,100W 访问?达到再想办法优化。改文件形式 IO 确定不是瓶颈?
    xiaotuzi
        4
    xiaotuzi  
    OP
       2019-09-04 17:40:44 +08:00
    @yinjy 就是入口对 url 解析,第一种先解析到插件目录调用同名控制器,第二种是根据控制器等查询注册的插件,再调用插件,最后调用系统方法。
    xiaotuzi
        5
    xiaotuzi  
    OP
       2019-09-04 17:45:22 +08:00
    @ben1024 加入缓存的话,类似读取本地缓存吗?那还是转为了文件存储,类似加载配置。
    xiaotuzi
        6
    xiaotuzi  
    OP
       2019-09-04 17:46:45 +08:00
    @tmkook 额,改为 include 引入配置的方式,会不会更好?注册插件的时候转为 json 存储到本地文件配置中,然后再入口引入配置。
    ben1024
        7
    ben1024  
       2019-09-04 20:07:48 +08:00
    @xiaotuzi 看使用频率,低频文件,高频 redis
    dvaknheo
        8
    dvaknheo  
       2019-09-05 18:53:37 +08:00
    嗯,类似功能最容易搞乱
    最开始,你替换就行
    后来,封装前后吧
    再后来,一个插件变多个
    再后来, 多个插件要有顺序

    看怎么适度而止了
    xiaotuzi
        9
    xiaotuzi  
    OP
       2019-09-06 06:51:16 +08:00 via iPhone
    @dvaknheo 已经知道解决方案了。因为全局控制器可以插件重定义,所以在入口的时候做插件调用是最方便的,但是如果一个方法加入了很多插件,就可能导致运行大大增加,同时实例化几个插件类比一个方法内直接写执行内容是不一样的,所以效率上,同个方法上写执行内容要快,但是没办法,插件本来就额外功能,我也保留了第一种插件制作方式,如果觉得插件注册太多,自己想办法集成到一个文件内也是可以的。
    关于第二种插件设计,先缓存 hook 表到缓存,每次方法只需要 foreach 去循环判断,有就执行,没有就跳过,不用一直访问数据库,一般人也不会一个方法加十几个插件进去吧…如果有,那就付费解决🌚
    ywisax
        10
    ywisax  
       2019-09-08 01:31:37 +08:00
    太局限了。这样设计的话,等于一个路由给多个回调,也就是在路由的 mapping 上做下手脚。
    既然提到 hook 了,就不如直接点,参考大部分现代框架的做法,将要打桩的上下文通过事件分发出去再收集回来,这样比你想的灵活多了。
    Youngxj
        11
    Youngxj  
       2019-09-10 16:27:20 +08:00
    一直想做插件模块,但是表单编程写久了,想不出来插件模块怎么搞了,难受
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2664 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 15:20 · PVG 23:20 · LAX 07:20 · JFK 10:20
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.