composer提示“package not installed”但composer.json已声明,主因是composer.lock中dist url失效(如github release删除)或vendor与lock状态不一致;需校验url可用性、清理对应镜像缓存目录并重建vendor和lock。

为什么composer install报“package not installed”但composer.json里明明写了?
这不是网络或权限问题,而是composer.lock记录的某个包 dist URL 已失效(比如 GitHub release 被删、镜像未同步、Packagist provider 数据过期),或本地 vendor/ 与 lock 文件状态不一致。Composer 在 install 阶段会严格校验 lock 中的 ZIP URL 是否可访问、SHA256 是否匹配,任一失败就中断并抛出该错误。
实操建议:
- 先运行
composer install --no-scripts --no-plugins,跳过自动脚本和插件干扰,确认是否纯依赖加载问题 - 检查报错中具体是哪个包失败,然后手动 curl 它的 dist URL:
curl -I https://api.github.com/repos/monolog/monolog/zipball/2.10.0(URL 来自composer.lock的dist.url字段) - 若返回 404 或 403,说明源已不可用;若返回 200 但
composer install仍失败,大概率是本地缓存的 provider 元数据没更新——此时要删~/.composer/cache/repo/https---...下对应镜像目录,而非只跑composer clear-cache
composer-unused扫不出的“幽灵依赖”有哪些?
它靠静态分析类名和命名空间引用,对动态加载、配置驱动、autoload 副作用完全无感。真正容易被漏掉的失效依赖集中在三类场景:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 通过字符串反射加载:比如
config/logging.php里写'handler' => 'Monolog\Handler\StreamHandler',但项目代码里根本没use或new过它 - Composer
autoload触发的全局副作用:如symfony/polyfill-mbstring在加载时注册mb_*函数别名,哪怕你代码里一行mb_strlen()都没写,它也不能删 - CI/CD 脚本里调用的
require-dev包:比如.github/workflows/test.yml中用了phpunit/phpunit,但composer-unused默认不扫描 YAML 文件
验证方式:删包后跑一次完整 CI 流程 + 手动触发所有配置加载路径(如访问 Laravel 的 /horizon 或 /telescope 页面),看是否报 Class not found。
怎么确认一个包是不是真“没用”,而不是“没被扫到”?
不能只信 composer-unused 输出,得组合验证:
- 先执行
composer show -t | grep "your/package",确认它在依赖树中是叶子节点(即没有其他包依赖它) - 再全局搜索:
grep -r "your/package" --include="*.php" --include="*.yml" --include="*.yaml" .,重点看 config/、tests/、.github/ 目录 - 如果搜不到任何引用,最后一步是临时注释掉
composer.json中的require行,运行composer update --dry-run—— 若没报冲突,且vendor/里确实没生成对应目录,才基本可判定失效
注意:Laravel、Symfony 等框架的自动发现机制(如 discovery autoload)会让某些包“静默生效”,删前务必查清它是否注册了 service provider 或事件监听器。










