简介
本参考面向DouPHP框架的插件开发者,系统化说明插件可使用的核心服务接口、数据库操作API、消息通知API、容器服务访问方法,以及事件系统与插件注册机制。文档重点覆盖:
- 事件系统:监听器注册、触发、优先级控制
- 容器服务:DI容器绑定、解析、上下文绑定、单例管理
- 插件注册与发现:manifest校验、Provider契约、Registry自动发现
- 数据库操作:ORM Builder链式查询与Facade DB用法
- 消息通知:统一消息门面
- 扩展下载入口:云端扩展资源访问(用于扩展分发)
项目结构
DouPHP将插件能力抽象为“契约 + 注册表 + 校验器”的组合:
- 契约层:定义插件应实现的接口(如支付、登录、配送等)
- 注册表:扫描并加载插件,提供统一的获取与查询能力
- 校验器:严格校验插件清单 manifest.php 的结构与安全约束
- 基础设施:事件系统、容器、ORM、门面等通用能力
graph TB
A["插件目录 plugin/*"] --> B["manifest.php<br/>声明 provider / plugin_group"]
B --> C["ManifestValidator<br/>白名单与命名空间校验"]
C --> D["Registry<br/>Connect/Payment/Shipping"]
D --> E["Container<br/>按FQCN实例化 Provider"]
E --> F["Provider 实现类<br/>实现契约接口"]
G["业务模块/控制器"] --> D
G --> H["事件系统 Event"]
G --> I["容器 Container"]
G --> J["ORM Builder / DB Facade"]
G --> K["消息 Message Facade"]
图示来源
- ManifestValidator.php:21-107
- ConnectPluginRegistry.php:92-164
- PaymentPluginRegistry.php:92-164
- Container.php:23-33
核心组件
- 事件系统:提供 listen/fire/dispatch/hasListeners/getListeners/forget/clear 等方法,支持优先级排序与批量结果返回
- 容器服务:轻量DI容器,支持 bind/singleton/factory/instance/alias/when()->needs()->give()、make()/call()、状态查询 has/bound/resolved/reset
- 插件契约与注册:通过 ManifestValidator 校验 manifest.php;通过 Registry 自动发现并按 pluginId 获取 Provider;各类型契约(支付、登录、配送)由对应接口定义
- ORM与DB:Builder 封装底层 Connection,支持链式查询与水合;DB Facade 提供便捷静态调用
- 消息通知:Message Facade 提供统一的消息发送能力
- 扩展下载:云端扩展详情与ZIP流式下载入口(用于扩展市场分发)
架构总览
插件与框架核心的交互路径如下:
- 插件通过 manifest.php 声明 provider 与 plugin_group
- 注册表在启动时扫描插件目录,校验 manifest,收集 Provider 类名映射
- 业务代码通过 Registry 获取具体 Provider 实例(由容器构造)
- 插件内部可使用事件系统、容器、ORM、消息门面等核心能力
sequenceDiagram
participant Boot as "启动/业务"
participant Reg as "Registry"
participant Val as "ManifestValidator"
participant Cont as "Container"
participant Prov as "Provider 实现"
Boot->>Reg : 请求获取某 pluginId 的 Provider
Reg->>Val : 校验 manifest.php 返回值
Val-->>Reg : 返回合法 provider FQCN
Reg->>Cont : make(provider FQCN)
Cont-->>Reg : 返回 Provider 实例
Reg-->>Boot : 返回 Provider 实例
图示来源
- ConnectPluginRegistry.php:92-164
- ManifestValidator.php:21-107
- Container.php:256-294
详细组件分析
事件系统 API
- 作用:为插件提供解耦的事件订阅与触发机制,便于在关键流程中注入自定义逻辑
- 主要方法
- listen(event, listener, priority=0):注册监听器,priority越大越早执行
- fire(event, ...params):触发事件,返回所有监听器的执行结果数组
- dispatch(event, ...params):fire 的别名
- hasListeners(event):检查是否有监听器
- getListeners(event):获取监听器列表
- forget(event):移除指定事件的所有监听器
- clear():清空全部监听器
- 使用建议
- 在插件初始化阶段注册监听器
- 对耗时监听器设置较低优先级,避免阻塞主流程
- 注意异常隔离,监听器内捕获异常,避免影响其他监听器
flowchart TD
Start(["调用 fire(event, ...)"]) --> Check{"是否存在监听器?"}
Check -- 否 --> ReturnEmpty["返回空数组"]
Check -- 是 --> Loop["按优先级顺序遍历监听器"]
Loop --> Call["调用回调并收集结果"]
Call --> Next{"还有下一个?"}
Next -- 是 --> Loop
Next -- 否 --> ReturnAll["返回结果数组"]
图示来源
- Event.php:61-81
容器服务 API
- 作用:提供依赖注入、对象生命周期管理与上下文绑定能力
- 主要方法
- bind(alias/concrete):绑定抽象到具体类(每次解析创建新实例)
- singleton(alias/concrete):单例绑定(首次解析后缓存)
- factory(alias, callable):工厂闭包绑定(覆盖先前 instance/单例缓存)
- instance(alias, $instance):直接注入已有实例(覆盖 factory)
- alias(alias, target):别名映射
- make($abstract, $parameters=[]):解析并创建实例(自动注入构造函数依赖)
- call($instance, $method, $contextOverrides=[]):调用对象方法并自动注入参数依赖
- when($consumer)->needs($abstract)->give($concrete):上下文绑定
- has/bound/resolved/forgetInstance/reset:状态查询与管理
- 使用建议
- 在插件引导阶段完成必要的绑定或工厂注册
- 使用上下文绑定为特定消费者切换实现,避免全局污染
- 谨慎使用单例,确保线程安全与测试隔离
classDiagram
class Container {
+bind(abstract, concrete)
+singleton(abstract, concrete)
+factory(abstract, factory)
+instance(abstract, instance)
+alias(alias, target)
+make(abstract, parameters)
+call(instance, method, contextOverrides)
+when(consumer) ContextualBindingBuilder
+has(abstract) bool
+bound(abstract) bool
+resolved(abstract) bool
+reset()
}
class ContextualBindingBuilder {
+needs(abstract) ContextualBindingBuilder
+give(concrete) void
}
Container --> ContextualBindingBuilder : "when()"
图示来源
- Container.php:23-509
插件注册与发现
- manifest.php 必须返回包含 plugin_group 与 provider 的数组
- ManifestValidator 进行白名单键校验、分组校验、provider FQCN 命名空间校验(要求以 Dou\Plugin\ 开头)
- Registry 扫描插件目录,读取 manifest.php,校验通过后记录 providerClassMap,并通过容器实例化 Provider
- 支持的分组:payment、connect、shipping
flowchart TD
Scan["扫描 plugin/* 目录"] --> Read["读取 manifest.php"]
Read --> Validate["ManifestValidator 校验"]
Validate --> |通过| Map["记录 providerClassMap[pluginId] = FQCN"]
Validate --> |失败| Skip["跳过该插件"]
Map --> Make["容器 make(FQCN) 实例化 Provider"]
Make --> Ready["Provider 可用"]
图示来源
- ManifestValidator.php:21-107
- ConnectPluginRegistry.php:121-164
- PaymentPluginRegistry.php:121-164
插件契约(接口)
- 配送插件契约 ShippingPluginProviderInterface
- pluginId():返回插件唯一ID(slug)
- meta():返回插件元信息(含 plugin_group、配置schema等)
- methods():返回配送方式列表(id/name/price/desc)
- 支付/登录契约:由各自 Registry 与接口约束(此处以 shipping 为例)
classDiagram
class ShippingPluginProviderInterface {
<<interface>>
+pluginId() string
+meta() array
+methods() array
}
图示来源
- ShippingPluginProviderInterface.php:21-46
数据库操作API
- ORM Builder:链式查询构造器,封装底层 Connection,支持 with 预加载、模型水合与 prefetch;终结方法 get/first/find/paginate 返回水合后的 Model/Collection;标量终结 count/sum/avg/max/min/value/exists/insert/update/delete 透传
- DB Facade:提供静态风格的数据库操作入口(如 table()->data()->insert() 等),适合快速脚本与迁移
- 使用建议
- 优先使用 ORM Builder 进行复杂查询与关联数据加载
- 使用参数化查询防止SQL注入
- 合理分页与字段选择,减少数据传输开销
flowchart TD
Q["构建查询 Builder"] --> Exec["执行终结方法"]
Exec --> Hydrate["模型水合与预加载"]
Hydrate --> Result["返回集合/模型/标量"]
图示来源
- Builder.php:25-31
- DB.php
消息通知API
- Message Facade:提供统一的消息发送能力,适用于站内信、邮件、短信等渠道的统一封装
- 使用建议
- 在插件中通过门面发送消息,避免直接耦合具体渠道实现
- 对消息内容进行转义与模板化处理,提升安全性与可维护性
扩展下载入口(云端)
- 根入口 extend.php 与 v1 入口 v1/extend.php 提供两类能力:
- rec=web|client:渲染扩展详情页HTML(供iframe嵌入)
- rec=down:校验后流式下载扩展zip(含付费扩展鉴权)
- 参数
- id:扩展唯一标识(需通过校验)
- user/password:下载付费扩展时的鉴权参数(POST)
- 行为
- 非法id返回404
- 鉴权失败返回403
- 成功则流式输出zip文件
sequenceDiagram
participant Client as "客户端"
participant Entry as "extend.php / v1/extend.php"
participant DL as "DownloadService"
Client->>Entry : GET ?rec=down&id=...&user=...&password=...
Entry->>DL : resolveExtendSource(id, user, password)
DL-->>Entry : {ok,url,filename} 或 失败原因
alt 成功
Entry->>DL : stream(url, filename)
DL-->>Client : 流式输出zip
else 失败
Entry-->>Client : 403 + 原因
end
图示来源
- extend.php:20-67
- v1/extend.php:18-65
依赖关系分析
- 插件与核心系统的耦合点
- 通过 Registry 获取 Provider 实例,降低与具体实现的耦合
- 通过 ManifestValidator 保证插件清单的安全性与一致性
- 通过 Container 管理依赖注入与生命周期
- 通过 Event 进行业务流程插桩
- 通过 ORM/DB 进行数据访问
- 通过 Message 进行通知发送
graph LR
Plugin["插件实现"] --> Reg["Registry"]
Reg --> Val["ManifestValidator"]
Reg --> Cont["Container"]
Plugin --> Ev["Event"]
Plugin --> ORM["ORM Builder / DB"]
Plugin --> Msg["Message"]
图示来源
- ConnectPluginRegistry.php:92-164
- ManifestValidator.php:21-107
- Container.php:23-509
- Event.php:21-138
- Builder.php:25-31
- Message.php
性能与注意事项
- 事件监听器
- 避免在高频事件中执行重计算或I/O操作
- 合理使用优先级,必要时拆分监听器
- 容器
- 单例仅用于无状态或线程安全的对象
- 工厂闭包适合需要延迟初始化或外部依赖的场景
- 数据库
- 使用分页与字段投影减少内存占用
- 避免N+1查询,利用预加载
- 扩展下载
- 大文件流式输出,避免一次性加载到内存
- 严格校验id与鉴权参数,防止越权访问
故障排查指南
- 插件未生效
- 检查 manifest.php 是否返回合法结构(plugin_group、provider)
- 确认 provider FQCN 符合命名空间规则
- 查看 Registry 是否正确发现并实例化 Provider
- 事件未触发
- 确认监听器已注册且事件名称一致
- 检查 fire/dispatch 调用位置与参数
- 容器解析失败
- 检查绑定/工厂/上下文绑定是否正确
- 查看 make() 抛出的依赖解析错误信息
- 数据库异常
- 检查SQL语句与参数绑定
- 确认连接配置与权限
- 扩展下载失败
- 检查id合法性与鉴权参数
- 查看日志中的 reason 字段定位原因
结论
DouPHP插件体系通过“契约 + 注册表 + 校验器”实现了高内聚、低耦合的扩展机制。插件可借助事件系统、容器、ORM、消息门面等核心能力,安全、稳定地集成到框架中。遵循本文档的最佳实践,可有效提升插件的可维护性与性能表现。
附录:常用API速查
- 事件系统
- 注册监听器:listen(event, listener, priority)
- 触发事件:fire(event, ...params)
- 检查监听器:hasListeners(event)
- 获取监听器:getListeners(event)
- 清理监听器:forget(event), clear()
- 容器服务
- 绑定:bind(), singleton(), factory(), instance(), alias()
- 解析:make(), call()
- 上下文绑定:when()->needs()->give()
- 状态:has(), bound(), resolved(), reset()
- 插件注册
- manifest.php:返回 {plugin_group, provider}
- Registry:按 pluginId 获取 Provider
- Validator:校验 manifest 结构与命名空间
- 数据库
- ORM:Builder 链式查询与终结方法
- Facade:DB::table(...)->... 快捷操作
- 消息通知
- Message Facade:统一消息发送
- 扩展下载
- 入口:extend.php / v1/extend.php
- 参数:id, user, password
- 行为:详情渲染与ZIP流式下载