composer outdated 默认只显示直接依赖,不检查间接依赖;加--all可查看全部,但需配合--minor-only、--no-dev等参数过滤,且结果受锁文件、缓存及镜像源影响。

composer outdated 默认只显示直接依赖,不是“所有过时包”——你看到的列表里根本不会有 monolog/monolog 这类被 laravel/framework 带进来的间接依赖,哪怕它已停更三年。
为什么 composer outdated 没列出你预期的包
它只扫描 composer.json 中 require 和 require-dev 下显式声明的包。间接依赖(transitive dependencies)默认完全不参与比对。常见误判场景:
- 运行
composer outdated后一片空白,但composer show monolog/monolog显示装的是v2.8.0,而 Packagist 上最新稳定版已是v3.5.0—— 因为monolog/monolog是通过其他包引入的,不在你的require列表里 - 某包显示
dev-main → dev-main,这不是“没更新”,是它没有稳定版号可比,outdated无法判断是否过时 - 私有仓库未在
repositories中配置,对应包压根不会出现在输出中
怎么真正看到全部过时包(含间接依赖)
加 --all 是唯一办法,但它会带来噪音,必须配合过滤:
-
composer outdated --all --minor-only:只看次版本更新,避开主版本跃迁风险 -
composer outdated --all --no-dev:排除require-dev包,聚焦运行时依赖 -
composer outdated --all --format=json | jq -r '.packages[] | select(.latest_status == "semver-major-update") | "\(.name) \(.installed.version) → \(.latest.version)"':用jq提取所有主版本升级项,避免人工漏看红色行 - 别信终端颜色 —— CI 环境常丢失 ANSI 色彩,
--no-ansi --format=json才是自动化唯一可靠路径
哪些“过时”其实不该动
版本号变大 ≠ 必须升级。关键要看约束是否允许、环境是否兼容:
-
"guzzlehttp/guzzle": "^7.0"锁着7.5.0,而7.9.2已发布 → 可安全升,补丁/次版本都在约束内 - 同一行显示
7.5.0 → 8.0.0 !→!表示已识别 BC-breaking 更改,哪怕只是次版本也要查UPGRADE.md -
phpunit/phpunit显示9.6.15 → 10.5.20,但项目config.platform.php设为"8.1"→10.x要求 PHP 8.2+,实际不可安装 -
composer outdated不检测漏洞,doctrine/dbal即使显示“最新”,也可能存在 CVE —— 必须单独跑composer audit
最常被忽略的一点:composer outdated 的结果基于本地 composer.lock 和缓存元数据。如果很久没跑 composer update --lock 或 composer clear-cache,它可能根本不知道远程已有新版。别扫完就以为“全盘掌控”,先同步元数据再判断。











