直接结论:phpstan 不分析隐式依赖,只校验类型;真正检测隐式依赖的是 composer-unused,它需配合正确扫描范围(如 --scan-dir=app)、先执行 composer install、并人工验证配置/反射/autoloader 副作用等场景。

直接结论:PHPStan 本身不分析“隐式依赖”,它只校验类型;真正能发现隐式依赖的是 composer-unused,但它必须配合正确扫描范围和运行前提,否则漏报率极高。
为什么 PHPStan 报 “Class not found” 不代表有隐式依赖
这是最常见的误解。PHPStan 的 Class not found 错误,99% 是路径没配对、autoload 没生效、或 vendor/autoload.php 根本没生成——它不关心你是否“悄悄用了某个包”,只关心“我能不能反射出这个类”。
隐式依赖(比如通过字符串拼接加载类、配置文件里写死的类名、或 class_alias() 注册的别名)PHPStan 压根不扫描,也不报错。
composer-unused 才是专治隐式依赖的工具
它静态扫描代码中所有 new、use、class_exists()、interface_exists()、trait_exists() 等调用点,再比对 composer.json 的 require 列表,标出未被引用的包。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 必须先跑
composer install,否则vendor/不全,结果不可信 - 默认只扫
src/,Laravel 项目要加--scan-dir=app --scan-dir=database --scan-dir=config - 测试代码里用的包,默认不扫,得显式加
--scan-tests - 动态类名(如
new $className)无法识别,这类包会被误标为“未使用” - 别忽略 autoload 的副作用:比如
symfony/polyfill-*包在加载时注册全局函数,composer-unused不会把它当“被使用”,但它实际是运行必需的
删包前必须人工验证的三类隐式场景
自动工具只能覆盖显式符号引用,以下情况必须人眼确认:
- 配置文件中硬编码的类名(如 Laravel 的
config/logging.php里写的'handler' => Monolog\Handler\StreamHandler::class) - 第三方包的插件机制(如 PHPUnit 的
phpunit.xml中<listener></listener>引用的类) - Composer 的
autoload.files或autoload.psr-4映射触发的副作用(例如某个包的bootstrap.php被 autoload 自动执行,注册了关键行为)
隐式依赖最难搞的不是“找不到”,而是“删了才暴露”——它往往藏在配置、反射、或自动加载的冷启动逻辑里。跑完 composer-unused 只是起点,不是终点。










