composer outdated 默认只检查 composer.json 中直接声明的依赖,不扫描间接依赖;需加 --all 才显示全部包,颜色和 ! 标识升级风险,安全漏洞须单独运行 composer audit。

composer outdated 默认只报你亲手写进 composer.json 的包,间接依赖(比如 laravel/framework 带进来的 symfony/http-foundation)压根不会出现在结果里——这不是 bug,是默认行为。想看到全部,必须加 --all。
为什么 composer outdated 看不到真正过时的包
常见现象:运行后输出寥寥几行,但项目一跑就报奇怪警告,或 CI 突然失败。根源在于 Composer 默认只扫描 require 和 require-dev 下显式声明的包,不递归检查传递依赖。
- 例如你装了
monolog/monolog,它被laravel/framework拉进来,而你没在composer.json里直接 require 它,那它就不会出现在默认输出中 -
dev-main或dev-develop版本不会标为 outdated,因为没有稳定版号可比;不是“没更新”,而是“没法比” - 带
(RC)或(beta)后缀的版本默认不显示,除非你设了"minimum-stability": "RC" - 如果本地缓存陈旧、镜像源同步延迟,或
composer.lock长期没更新,outdated也会漏报
怎么用 composer outdated 真正看清风险
颜色和符号比版本号本身更关键。终端里黄色行(如 symfony/console v5.4.32 → v5.4.37)表示补丁更新,大概率安全;红色行(v5.4.32 → v6.0.19)说明约束允许主版本跃迁,但极可能破坏兼容性;带 ! 的行(如 doctrine/dbal 3.6.4 → 3.7.0 !)是 Composer 自动识别出的 BC-breaking 更改,哪怕只是次版本也得查 CHANGELOG。
- 加
--all才能看到所有已安装包,包括间接依赖和suggest里的可选包 - 加
--major-only快速聚焦高风险项:composer outdated --major-only - 加
--security-only筛选已知存在安全通告的包(需先运行过composer audit或启用security-advisories插件) - 加
--format=json输出结构化数据,配合jq过滤才可靠:composer outdated --all --format=json | jq -r '.packages[] | select(.latest_status == "major") | "\(.name) \(.installed.version) → \(.latest.version)"'
composer outdated 不等于能安全升级
它只告诉你“有哪些可升”,不保证升完能通过测试、不冲突、不破坏现有逻辑。很多团队误以为 outdated 列出来的包都能直接 composer update vendor/package,结果卡在依赖冲突或 PHP 版本不匹配上。
- 先确认目标包是否真被你的代码直接调用:用
composer depends vendor/package查谁在依赖它 - 再模拟真实升级路径:
composer update vendor/package --dry-run,它会提前暴露冲突、降级或删除行为 - 别跳过该包的
UPGRADE.md或 GitHub Releases 里的Breaking Changes小节 -
composer show vendor/package能看到实际安装版本、远程最新版、以及它自己的require约束,比outdated更底层
自动化监控不能只靠 composer outdated
CI 中直接跑 composer outdated 容易误报:网络抖动导致元数据拉取失败、镜像源同步延迟、缓存未刷新、甚至不同 Composer 版本对参数支持不一致(如老版不认 --security-only)。
- 务必加
--no-cache避免本地缓存干扰 - 用
--direct --minor-only --format=json输出,再脚本解析,比人眼扫终端靠谱得多 -
composer outdated不检测漏洞,doctrine/dbal即使显示“最新”,也可能存在 CVE —— 必须单独跑composer audit - 某些包被
replace或provide替代(如用symfony/polyfill替代原生函数),默认不显示,要强制检查得加--all --no-dev
最常被忽略的一点:outdated 的结果基于当前 composer.lock 和本地缓存元数据。如果项目长期没跑 composer update --lock 或 composer clear-cache,它看到的“最新版”可能已经滞后数周。


















