Laravel必须用Larastan而非裸PHPStan,因其专为Laravel“魔法”特性设计,能准确推断模型字段、Eloquent关系、门面返回类型等;裸PHPStan则因无法理解动态特性而大量误报或漏检。

PHPStan(配合 Larastan)不是“锦上添花”的工具,而是你在写完 php artisan make:model User 后,立刻就能靠它发现 $user->non_existent_field 这类错误的守门人。不配,就等于默认接受大量运行时才暴露的类型漏洞。
为什么 Laravel 必须用 Larastan,而不是裸 PHPStan
Laravel 的门面、模型动态属性、服务容器绑定、Eloquent 关系等全是“魔法”,裸 PHPStan 看不懂,会疯狂报错或直接跳过——比如把 User::find(1) 当成返回 Model 而非 User,导致后续所有属性访问都失准。
Larastan 是专为这些魔法写的扩展,它能:
- 从数据库迁移自动推断模型字段类型(
$user->email→string) - 识别
belongsTo()返回的是BelongsTo<User, $this>,而非模糊的object - 理解
Auth::user()在已认证上下文里返回User|null,而非mixed
没它,PHPStan 在 Laravel 项目里基本是“睁眼瞎”;有它,才能真正落地类型安全。
立即学习“PHP免费学习笔记(深入)”;
level 5 是唯一合理起点,别一上来就 level 8
刚加 Larastan 就设 level: 8,等于让团队面对几百个报错放弃使用。真实项目中,level: 5 已覆盖变量类型、方法存在性、基础返回值检查,且误报率极低。
推荐渐进路径:
-
level: 5:跑通 CI,修复所有红标错误(如调用不存在的方法) -
level: 6:开启checkMissingIterableValueType: true,强制集合元素类型声明(Collection<User>) -
level: 7:启用inferPrivatePropertyTypeFromConstructor: true,让构造函数参数自动推导私有属性类型
别碰 level: 8,除非你已手动补全全部模型字段注解、关系返回类型、以及所有 Facade 的 PHPDoc。
phpstan.neon 配置里最容易漏掉的三项
很多团队配完就跑,结果 phpstan analyse 依然不报 Eloquent 关系错误,或忽略 config('app.name') 类型——问题往往出在配置缺了这三样:
-
bootstrapFiles: ['vendor/autoload.php']:不加这个,Laravel 框架类根本加载不进来,AppServiceProvider里的代码全当黑盒 -
paths: ['app/', 'database/']:只扫src/?那模型、迁移、服务提供者全被跳过,静态分析形同虚设 -
includes: ['- vendor/larastan/larastan/extension.neon']:注意是-开头的相对路径,不是./vendor/...;写错路径会导致 Larastan 扩展完全未加载
漏掉任意一项,你看到的都不是 Laravel 项目的实际类型状态,而是“猜”的结果。
CI 中运行 phpstan analyse 的两个硬性要求
本地能过 ≠ CI 能过。常见翻车点集中在环境和内存:
- 必须显式指定
--memory-limit=2G或--memory-limit=-1:Laravel 大项目分析时 PHPStan 常因内存超限直接退出,报错类似Allowed memory size of 134217728 bytes exhausted - CI 环境要先执行
composer install --no-interaction --prefer-dist:否则vendor/autoload.php缺失,bootstrapFiles失效,所有类型推断崩盘
更隐蔽的问题是:某些 CI runner 默认用 PHP 8.0,而 Larastan ^3.0 要求 PHP 8.2+,版本不匹配会导致 extension.neon 加载失败,却无明确提示——建议在 CI 步骤开头加 php -v 和 php --ini 校验。
最常被忽略的其实是模型字段与数据库迁移的同步:PHPStan 依赖迁移文件推断字段类型,但如果你用 DB::statement() 直接建表、或长期不更新迁移,$user->created_at 就可能被当成 mixed。这不是工具的问题,是代码与基础设施脱节的信号。



















