Composer的require字段只接受注册包名与版本约束,不可写路径或Git URL;正确写法如"monolog/monolog": "^2.10",本地包需通过repositories配置path类型。

require 里写包名和版本号,不是写路径或本地文件
很多人误以为 require 字段可以填本地路径、Git URL 或相对目录,比如 "my/package": "./libs/my-package" —— 这在标准 Composer 工作流中不生效(除非你额外配了 repositories 且类型为 path)。Composer 的 require 只认「已注册包名 + 版本约束」。
- 正确写法是
"monolog/monolog": "^2.10",包名必须和 Packagist 上完全一致(含大小写) - 版本号支持多种写法:
"^1.2"(兼容性更新)、"~2.0.0"(补丁+小版本)、"dev-main"(分支别名,需配合minimum-stability) - 如果真要引用本地开发中的包,得在
composer.json顶层加repositories,且类型设为path,否则require里写路径会被忽略
dev-main 和 dev-develop 别乱用,稳定版优先
dev-main 看起来“最新”,但实际是不稳定快照:每次 composer install 都可能拉到不同 commit,CI 构建不可重现,上线前也难锁定问题来源。
- 生产环境严禁用
"vendor/package": "dev-main",连"dev-develop"都不建议 - 如果包没发正式版(比如只有
v1.0.0-beta),用"1.0.0-beta"显式声明,再配"minimum-stability": "beta" -
dev-*分支别名依赖会跳过 Packagist 的版本校验,Composer 默认不缓存其元数据,安装慢、失败率高
require-dev 和 require 的边界必须分清
require-dev 里的包只在本地开发和测试时加载,composer install --no-dev 会直接跳过它们。但很多人把 PHPUnit、phpstan 这类工具错放到 require,结果线上容器白装一堆无用依赖。
-
require放运行时必需的:比如"guzzlehttp/guzzle"、"symfony/http-foundation" -
require-dev放开发期工具:比如"phpunit/phpunit"、"friendsofphp/php-cs-fixer" - 执行
composer install时若没加--no-dev,require-dev也会装;但线上部署应始终加该参数,避免污染
版本约束写太宽,后期升级踩坑概率翻倍
写 "^1.0" 看似省事,但等包升到 1.9.0,API 可能已悄然变更。更隐蔽的是,某些包在小版本里改了 PHP 兼容性(比如从 ^7.4 升到 ^8.0),而你的项目还没准备好。
- 新项目建议用
"1.5.*"或"1.5.3"锁死最小可用版本,后续手动升级 - CI 中跑
composer update --dry-run能提前发现潜在冲突,但别依赖它代替人工验证 -
composer.lock是真实依赖快照,删了重生成等于放弃版本控制——哪怕只是改一行require,也要commit lock 文件
最常被忽略的一点:Composer 不会自动检测 require 里写的包是否和当前 PHP 版本兼容。错误往往出现在 composer install 半途报 Your requirements could not be resolved,但真正原因可能是某个间接依赖要求 PHP 8.2,而你还在跑 8.0 —— 这时候得看 composer why-not php:8.2,而不是盯着 require 字段反复改版本号。











