虚拟包是声明“能力”或“替代关系”的元信息占位符,不提供代码,仅通过provide字段定义接口/扩展等契约;官方认可的包括ext-json、psr/log、php等,roave/security-advisories是唯一需置于require-dev的反向虚拟包。

Composer 虚拟包(virtual packages)不是真实可安装的包,而是用于声明“能力”或“替代关系”的元信息占位符 —— 它们本身不提供代码,但能强制 Composer 在解析依赖时做出特定选择。误用会导致 composer install 失败、composer why 查不到来源、甚至 CI 构建卡死。
虚拟包到底是什么,哪些是官方认可的
虚拟包是仅在 composer.json 的 provide 字段中声明的包名,没有实际 dist/source,也不出现在 Packagist 上。它们的作用是告诉 Composer:“我(当前包)提供了某个接口/能力,等价于另一个包”。
常见且被广泛支持的包括:
-
ext-json、ext-pdo、ext-gd等扩展名 —— PHP 扩展本身是虚拟包,由config.platform或运行时环境“提供” -
php本身也是虚拟包,版本约束如"php": "^8.1"实际匹配的是当前运行环境的 PHP 版本 -
psr/log、psr/container等 PSR 接口包 —— 它们不包含实现,只定义契约;真正提供实现的是monolog/monolog或symfony/dependency-injection -
roave/security-advisories是个特例:它本身是真实包,但所有版本都只含conflict规则,作用是“阻止安装已知不安全的版本”,属于“反向虚拟包”
什么时候该用 provide,而不是 require
你写的是一个库(library),且它实现了某个标准接口但不想硬绑定具体实现时,才用 provide。比如你开发了一个自定义日志处理器,兼容 psr/log,但不依赖 monolog/monolog,就可以这样声明:
"provide": {
"psr/log": "1.0.0"
}
这表示:“只要项目里有任意满足 psr/log 的实现(比如 monolog/monolog 或 slim/slim 自带的),我就能工作”。
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
反例:在 Laravel 应用(项目)的 composer.json 里写 "provide": {"psr/log": "1.0.0"} 是无效的 —— 项目不提供能力,只消费能力;这么做会让 Composer 认为“已满足日志需求”,反而可能跳过安装 monolog/monolog,导致运行时报 Class not found。
provide 写错的典型症状和修复方式
现象包括:composer install 报 Root composer.json requires psr/log ^2.0, found psr/log[dev-main] but the package is virtual;或者 composer why psr/log 返回空,但项目又确实用了日志功能。
- 检查是否把
provide放在了项目级composer.json里 —— 删除它,改用require明确引入实现 - 确认
provide的版本号是否与下游要求匹配,比如你写"provide": {"psr/log": "1.0.0"},但依赖项要求^2.0,就不兼容 - 若用
config.platform声明扩展(如"ext-gd": "1.0"),确保实际环境中该扩展已启用,否则composer install会因平台缺失失败 - 虚拟包不能被
composer require安装 —— 运行composer require psr/log实际安装的是psr/log的桥接包(meta package),而非接口本身;真要装,得composer require monolog/monolog
roave/security-advisories 是唯一需要放进 require-dev 的虚拟包
它是唯一一个靠“冲突规则”起作用的虚拟包,必须放在 require-dev,且不能放 require。原因:
- 它不提供任何类或功能,放进
require会导致生产环境多装无用依赖 - 它的作用是在
composer update阶段检查冲突,CI 流水线需触发此检查,所以必须在require-dev中存在 - 如果项目用了
--no-dev部署,它自然被跳过,不影响运行时 - 错误写法:
"require": {"roave/security-advisories": "dev-master"}—— 这会让生产部署失败,因为 Composer 会尝试安装这个“空包”,而它没有 dist
真正容易被忽略的是:一旦你把它加入 require-dev,每次 composer update 都会严格拦截已知漏洞版本 —— 即使你没显式执行 composer audit。这个行为不可关闭,也不建议绕过。










