可扩展的 Composer 类库依赖 PSR-4 严格对齐、显式 autoload 配置、清晰命名空间边界及接口驱动设计,而非抽象类或预留接口;需避免 final、硬编码依赖、extra 运行时配置及职责混杂。

可扩展的 Composer 类库不是靠“预留接口”或“写一堆抽象类”实现的,而是靠严格遵循 PSR-4 + 显式 autoload 配置 + 清晰的命名空间边界,让使用者能安全地替换、装饰、继承或 patch 具体类。
PSR-4 命名空间必须与目录结构完全对齐,且不依赖自动发现
很多人把 src/Http/Client.php 里声明 namespace MyLibHttp;,却在 composer.json 中写 {"MyLib\": "src/"} —— 这会导致 MyLibHttpClient 永远加载失败。PSR-4 是前缀映射,不是路径猜测。
-
composer.json中的 autoload 映射必须精确到最短公共命名空间前缀,例如{"MyLib\Http\": "src/Http/"}或{"MyLib\": "src/"},二者不可混用 - 子命名空间如
MyLibContracts必须显式覆盖,否则use MyLibContractsHttpClientInterface;会报错 Class not found - 不要依赖
classmap或files来“兜底”——它们无法被下游项目继承或重写,破坏可扩展性
避免 final class 和 private 方法,但要用 type hints 和 contracts 约束行为
一个类是否可扩展,不取决于它有没有 extends 关键字,而取决于它是否允许被继承、方法是否可重写、构造参数是否可替换。PHP 的 final 是扩展性杀手,但盲目开放所有方法又会导致契约崩坏。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 核心行为应定义在 interface 或 abstract class 中(如
HttpClientInterface),具体实现类(如GuzzleHttpClient)只负责适配,不封装逻辑 - 构造函数参数必须是接口或抽象类型,禁止硬编码依赖具体类(如
new GuzzleHttpClient()) - 配置项通过
__construct(array $options = [])或 builder 模式注入,不读取全局$_ENV或静态配置
extra 配置不能替代依赖注入,但可用于运行时开关
你可能会想在 composer.json 的 extra 字段里加 "debug": true,然后在代码里读取它 —— 这看似灵活,实则危险:extra 只存在于根项目中,一旦你的类库被 A 包依赖,A 包又被 B 包依赖,B 就完全无法控制这个开关。
- 真正需要可配置的行为(如日志级别、重试次数)必须走构造参数或 setter,而不是从
$composer->getPackage()->getExtra()动态读取 - extra 只适合做“安装时一次性决策”,比如是否发布调试命令、是否注册服务提供者(Laravel 场景),不适合影响运行时逻辑流
- 若必须用 extra,务必做空判断:
$extra = $composer->getPackage()->getExtra() ?? [];,否则在无 extra 的项目中直接 fatal error
autoload 之外的扩展点:ServiceProvider 和 Plugin 接口要分离
很多 PHP 框架(Laravel、Symfony)靠 ServiceProvider 注册服务,而 Composer 插件靠 PluginInterface 注入行为。这两者目标不同,不能混为一谈 —— 类库本身不该强耦合某框架的 ServiceProvider,也不该自己实现 PluginInterface。
- 类库只提供标准 PSR-4 结构和清晰 contracts;框架集成层(如
laravel-package)才负责写ServiceProvider - Composer 插件是独立包,type 必须为
composer-plugin,且主类实现PluginInterface;它不应和业务类库共存于同一仓库 - 如果你发现自己的类库里出现了
class MyServiceProvider extends ServiceProvider或implements PluginInterface,说明职责已经泄漏 —— 这会让下游无法选择性加载功能
最常被忽略的一点:可扩展性不体现在你写了多少 hook,而体现在别人删掉你某一行代码后,系统是否仍能跑通。所有扩展机制(事件、装饰器、策略模式)都该有明确 fallback,而不是抛出未捕获的 ClassNotFoundException 或静默跳过逻辑。

















