通配符匹配版本号中明确写出部分之后的所有合法组合,如”2.”等价于”>=2.0.0 =6.4.0

在 composer 中,*(通配符)是一种简洁的版本约束写法,用于匹配某一位版本号的所有可能值,但它隐含的行为和潜在风险常被低估。
通配符 * 的匹配规则
通配符只作用于版本号中被明确写出的部分之后的字段,且默认包含下界、不包含上界。它不是“任意版本”,而是“该段及以下所有合法组合”。
-
"monolog/monolog": "2.*"等价于">=2.0.0 —— 匹配所有 2.x.y 版本,包括 2.10.0、2.99.99,但跳过 3.0.0 -
"symfony/http-foundation": "6.4.*"等价于">=6.4.0 —— 只允许补丁更新,不升级小版本 -
"phpunit/phpunit": "10.*.*"是无效写法 —— Composer 不支持多星号,会报错或忽略
为什么用 * 而不是 ^ 或 ~?
它适合那些你明确想锁定主版本(或主+次版本),又不想手动写范围、也不愿让 ^ 在 0.x 场景下行为突变的场景。
- 当你维护一个长期兼容 PHP 8.1 的老项目,依赖包只要求“必须是 7.x”,用
"doctrine/orm": "7.*"比"^7.0"更直白,也避免了^7.0在未来某天意外匹配到 8.0-alpha(如果稳定性设置宽松) - 某些生态(如 Symfony 组件)推荐使用
X.Y.*形式来强调“仅接受该小版本内的补丁修复”,语义更清晰
主要风险:表面宽松,实则失控
通配符本身不危险,危险的是它掩盖了版本演进的真实节奏和维护者意图。
-
"laravel/framework": "10.*"看似安全,但如果 Laravel 10.40 发布了一个破坏性变更(比如移除了某个长期标记为@deprecated的方法),而你没做回归测试,就可能在下次composer update后直接报错 - 当包作者跳过多个补丁版本(如从 10.2.1 直接发 10.2.15),
10.*会全量接受——你无法预知中间是否混入了未充分测试的改动 - 它不区分稳定性和开发版:若包存在
10.3.0-RC1或10.3.0-beta2,而你的minimum-stability是stable,它们不会被选中;但设为beta或dev时,10.*就可能拉入预发布版,导致环境不稳定
实用建议:何时用、怎么控
通配符不是“偷懒写法”,而是有明确边界的控制手段。用对了省心,用错了埋雷。
- 生产项目中,优先用
^(如"^10.0"),它遵循 SemVer 且 Composer 默认策略更稳健;仅在需要显式排除次版本升级时,才换"10.*" - 搭配
composer.lock使用——无论你写的是*还是^,只要 lock 文件存在,composer install就只会装记录的精确版本,这是真正防风险的第一道闸 - 定期运行
composer outdated查看哪些*约束已实际安装了较新补丁,再结合 CHANGELOG 判断是否需手动冻结(比如改成"10.3.*") - 避免在根项目中对核心框架用
*",例如"laravel/framework": "*"—— 这等于放弃所有版本控制,等同于"dev-main"风险级别
基本上就这些。通配符不复杂,但容易忽略它的“无条件向下兼容”假象——它不管作者有没有守 SemVer,只管数字匹配。