composer outdated 检查 composer.lock 中已安装版本与 composer.json 约束下可安全升级的最高兼容版本之间的差异,仅显示满足当前约束但本地版本更旧的包。

composer outdated 命令到底检查什么
composer outdated 不是简单列出所有包的最新版,而是对比 composer.lock 中记录的已安装版本与当前 composer.json 约束下**可升级到的最高兼容版本**。它只显示那些“满足当前版本约束、但本地装得更旧”的包——换句话说,这些包确实可以安全更新,只是还没执行 composer update。
常见误解:以为它会标出“全网最新版”,其实不会。比如你锁定了 "monolog/monolog": "^2.0",而 2.10.0 已发布,但 2.9.0 是当前满足约束的最高版,那 outdated 就只会拿 2.9.0 和你 lock 里的 2.7.0 比,不提 2.10.0。
如何精准筛选过期包(避免信息过载)
默认输出包含 dev 包和所有依赖层级,实际维护时往往只需要关注直接依赖。用这些参数快速聚焦:
-
composer outdated --direct:只显示composer.json中显式声明的包(即你手动 require 的),忽略传递依赖 -
composer outdated --minor-only:仅报告小版本更新(如 3.2.1 → 3.2.5),跳过主版本或次版本变动(3.x → 4.x 或 3.2 → 3.3) -
composer outdated --outdated:强制只显示“有更新”的行(默认已如此,但某些旧版 Composer 需显式加) -
composer outdated --format=json:输出 JSON,方便脚本解析或 CI 中断构建逻辑
为什么有时 outdated 显示“无更新”但 update 却能升级
典型原因有三个:
- 你的
composer.json里用了太宽泛的约束,比如"^1.0",但composer.lock锁的是 1.2.0;而上游新发布了 1.3.0 —— 这种情况outdated会显示它,但如果你之前运行过update并失败(比如因冲突回退),lock 文件可能没刷新,导致误判 - 你本地修改过
composer.lock手动降级某个包,但没运行install,此时 lock 和 vendor 不一致,outdated仍按 lock 判断,结果失真 - 启用了
minimum-stability或prefer-stable,而新版本是 RC 或 dev 分支,outdated默认忽略不稳定版本,但update加--with-dependencies可能拉下来
CI/CD 中自动检测过期依赖的实用写法
想在流水线里卡住“关键依赖长期不更新”,别只靠人肉看输出。推荐这个组合:
composer outdated --direct --minor-only --format=json | jq -r 'to_entries[] | select(.value.latest != .value.installed) | .key' | grep -E '^(guzzlehttp/guzzle|symfony/.*|laravel/framework)$'
说明:
- 先用
--direct --minor-only缩小范围 -
jq提取真正存在差异的包名 -
grep白名单过滤核心框架/HTTP 客户端等高风险依赖 - 如果输出非空,就
exit 1让构建失败,倒逼更新
注意:jq 需预装;若不用 JSON,纯文本解析容易被颜色字符或空格干扰,可靠性低。
真正难的不是跑命令,而是判断“该不该升”——比如一个 patch 版本修复了安全漏洞,就必须升;但另一个 minor 版本悄悄改了事件监听器签名,就得先读 CHANGELOG。这些决策,outdated 不会替你做。










