psalm必须作为dev依赖安装并执行psalm --init生成配置;初始化选medium规模,手动将errorlevel调至1或2,确保指向正确源码目录,添加tests目录需显式声明,ci需分阶段安装,resolvefromconfigfile="true"是启用自定义配置的关键。

Psalm 必须作为 dev 依赖安装,不能全局或 PHAR 方式用于项目级类型检查;否则 psalm.xml 路径解析、autoloader 集成和 CI 可重现性都会出问题。
composer require --dev vimeo/psalm 后必须立刻跑 psalm --init
不执行这一步,psalm.xml 不会生成,所有后续配置都无从谈起。注意:psalm --init 会交互式询问项目规模(small/medium/large),选 medium 最稳妥——small 容易漏掉深层调用链问题,large 则默认开启大量严格规则,新手直接卡住。
- 它会自动扫描当前目录下疑似源码的文件夹(如
src、lib、app),但常猜错;生成后务必检查<directory name="src"></directory>是否真指向你的主代码目录 - 生成的
errorLevel默认是4,对新项目偏松:关键问题如InvalidReturnType、MissingParamType在 level 1–3 才强制报出,建议初始化后手动改为1或2 - 若项目含测试代码且需分析(比如
tests/下有数据提供器类),得在<projectfiles></projectfiles>里额外加一行<directory name="tests"></directory>,否则class_exists()返回 true 也照样报 “Unable to resolve class”
为什么 composer install --no-dev 后 Psalm 失效?
因为 vimeo/psalm 在 require-dev 里,--no-dev 会跳过安装,导致 vendor/bin/psalm 文件消失。CI 中常见错误是部署脚本先 composer install --no-dev,再试图运行 Psalm——这必然失败。
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
- 正确做法:CI 分两阶段,先
composer install(带 dev)跑 Psalm,通过后再用--no-dev构建生产包 - 如果部署流程硬性禁止 dev 依赖上线,可在
composer.json的scripts里写"psalm-ci": "composer install --no-interaction && vendor/bin/psalm --no-cache --threads=2",确保分析环境完整 - 别试图用
autoloader="vendor/autoload.php"强行“修复”——Psalm 本来就会读这个文件,加了反而可能覆盖默认行为,引发路径解析错乱
Unable to resolve class Xyz 真正该查什么?
这不是 Psalm 的 bug,是 autoloader 链路断在了 Composer 层。90% 情况下,php -r "var_dump(class_exists('Xyz'));" 返回 false 就能定位根源。
- 先确认
composer dump-autoload是否执行过——尤其新增 PSR-4 映射或改过composer.json后,不跑这句,Composer 根本不认新类 - 检查
composer.json的autoload段:命名空间拼错(如"App\"写成"App\"少个反斜杠)、路径不存在("src/"实际是"app/src/")都会导致class_exists()失败 - 第三方扩展(如
ext-redis)没有 PHP 类文件,才需要<stubs></stubs>;此时必须手写完整 stub(含class Redis声明和方法签名),并显式写进psalm.xml,只放目录或空<stubs></stubs>标签无效
最容易被忽略的是 resolveFromConfigFile="true" 这个属性:不加它,Psalm 会忽略你写的 <stubs></stubs>、<plugins></plugins> 和自定义 <issuehandlers></issuehandlers>,所有手动配置形同虚设。每次改完 psalm.xml,记得核对根节点是否有这个 flag。










