provide 字段必须写在包自身的 composer.json 根层级,格式为 {"provide": {"vendor/name": "version"}},用于声明该包实现某个虚拟包(如 psr/log-implementation),供 Composer 在依赖解析时匹配替代,而非在根项目中声明自身提供能力。

provide 字段写在哪、怎么写才生效
它只在根 composer.json 或被安装的包自己的 composer.json 里起作用,且必须是顶层字段,不能嵌套在 require 或其他区块里。
常见错误是把它当成“我当前项目提供什么”的声明写在根 composer.json 中——其实没用,Composer 只在解析依赖图时检查已安装包的 provide,用来替代虚拟包(如 psr/log-implementation)的自动匹配。
-
provide是包作者写的,不是使用者写的;你作为用户,一般只在 require 某个包时“被动受益”于它的provide - 格式必须是
{"provide": {"vendor/name": "version"}},其中vendor/name是虚拟包名(如psr/http-client-implementation),version推荐写*,避免因版本号不匹配导致 fallback 失败 - 如果同时声明了
require和provide同一个包(比如自己写了"psr/log": "^3.0"又"psr/log-implementation": "*"),Composer 不会报错,但可能让其他包误判实现可用性
为什么 require psr/log-implementation 却装了 monolog/monolog
因为 monolog/monolog 的 composer.json 里写了 "provide": {"psr/log-implementation": "*"},而你在 require 中写了 "psr/log-implementation": "^1.0" ——Composer 把这当成一个“虚拟包”,然后去找真正提供它的包,找到 monolog 就装它。
这个机制不是 magic,而是 Composer 在构建依赖图时做的隐式替换:把所有 provide 声明注册为可满足的“能力”,再按语义版本规则匹配。
- 虚拟包本身没有代码,不能被
autoload,也不能use;它只是个占位符,用于解耦接口和实现 - 如果你 require 的是
psr/log-implementation,但本地已有slim/slim(它也 providepsr/log-implementation),Composer 仍会装 monolog,除非你显式 requireslim/slim并禁用 packagist 默认行为 - 运行
composer show --platform可看到当前环境中哪些虚拟包已被满足,以及由谁提供
provide 写错会导致 autoload 失败吗
不会。autoload 完全由 autoload 和 autoload-dev 字段控制,和 provide 无关。但写错会让人误以为某接口可用,结果运行时报 Class not found。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
典型翻车场景:包声称提供 psr/cache-implementation,却没 autoload 对应的 PsrCacheCacheInterface 实现类,或者实现类路径根本没注册。
-
provide是承诺,不是保证;它不校验类是否存在、是否符合接口契约 - 如果提供的是自定义虚拟包(如
myorg/queue-driver),下游包通过require它来触发安装,但若你的包没正确 autoload 具体驱动类,运行时照样崩 - 测试时别只看
composer install成功,要验证实际调用链中接口是否真能 resolve 到你的实现类
想让自己的包被当成某个虚拟包的实现,该怎么做
在你包的 composer.json 里加 provide,同时确保:autoload 正确映射实现类,且这些类真实实现了对应 PSR 或自定义接口。
例如你要发布一个轻量日志器并希望被识别为 psr/log-implementation:
{
"name": "acme/tiny-logger",
"provide": {
"psr/log-implementation": "*"
},
"autoload": {
"psr-4": {
"Psr\Log\": "src/"
}
}
}
- 不要漏掉
require对应的接口包(如"psr/log": "^3.0"),否则用户无法 type-hint - 如果实现类不在标准命名空间下(比如你用了
AcmeLogger而非PsrLogLoggerInterface),provide就是误导,下游无法安全依赖 - 发布到 Packagist 后,别人
require "psr/log-implementation"时,Composer 才会考虑你的包;本地开发测试请用pathrepo 或repositories配置临时指向
最常被忽略的一点:虚拟包的名称必须和下游 require 的字符串完全一致,包括大小写和连字符——写成 psr/log_implementation 或 PSR/Log-Implementation 都不会匹配。

















