升级Laravel 10后Larastan集合方法参数报错问题
升级Laravel 10后,出现大量Larastan报错,集中在map、reduce等集合方法的类型不匹配上。
问题示例
原正常运行的代码:
return $this->articleRepository->getDefaultArticles($organizationId) ->toBase() ->map(function (Article $article) { return new Content( $article->id, $article->title, $article->language, ); }) ->toArray();
抛出错误:
Parameter #1 $callback of method Illuminate\Support\Collection<(int|string),Illuminate\Database\Eloquent\Model>::map() expects callable(Illuminate\Database\Eloquent\Model, int|string): App\Academy\Content,
Closure(App\Models\Article): App\Academy\Content given
仓库方法已添加正确的类型提示:
/** * @return Collection<Article> */ public function getDefaultArticles(OrganizationId $organizationId): Collection { /** @var Collection<Article> */ return Article::query() ->where('organization_id', $organizationId) ->get() ->keyBy('id') ->values(); }
临时解决方案是用带类型提示的临时变量,但需要重复上百次,且IDE提示该操作无必要:
/** @var Collection<Article> $articles */ $articles = $this->articleRepository ->getDefaultArticles($organizationId) ->toBase();
高效解决方案
1. 更新Larastan到最新版本
Laravel 10的兼容性问题可能已被修复,执行更新:
composer update nunomaduro/larastan
更新后重新运行Larastan分析,看报错是否消除。
2. 修复toBase()的类型推断偏差
Larastan对toBase()的泛型类型继承存在问题,可通过配置扩展修正:
在项目的phpstan.neon中添加:
services: - class: PHPStan\Type\Laravel\Eloquent\CollectionToBaseExtension tags: - phpstan.broker.methodTypeExtension
如果默认没有该扩展,可自定义一个简单的类型扩展,让toBase()返回与原集合相同泛型参数的基础Collection。
3. 全局配置增强集合类型推断
在phpstan.neon中配置Larastan的模型集合扩展,确保链式调用时泛型类型不丢失:
parameters: larastan: modelExtensions: - App\Extensions\CustomModelCollectionExtension
自定义CustomModelCollectionExtension来优化集合方法链式调用的类型推断逻辑。
4. 批量添加内联类型提示(无需临时变量)
用IDE的全局替换功能,在链式调用的起始处添加内联类型注释,替代临时变量:
/** @var Collection<Article> */ return $this->articleRepository->getDefaultArticles($organizationId) ->toBase() ->map(function (Article $article) { return new Content( $article->id, $article->title, $article->language, ); }) ->toArray();
这种方式比临时变量更简洁,且能批量处理所有报错。
内容的提问来源于stack exchange,提问作者Fabio Sasso

