如何解决如何让 phpstan 推断我的 Laravel Collection 管道的类型?
给我的班级
<?PHP
declare(strict_types=1);
use Illuminate\Support\Collection;
use stdClass;
class PHPstanIssue
{
/**
* @param Collection<Collection<stdClass>> $collection
*
* @return Collection<Foo>
*/
public function whyDoesThisFail(Collection $collection): Collection
{
return $collection
->flatten() // Collection<stdClass>
->map(static function (\stdClass $std): ?Foo {
return Foo::get($std);
}) // should Now be Collection<?Foo>
->filter(); // should Now be Collection<Foo>
}
}
我很困惑为什么 PHPstan (0.12.64) 会失败:
18: [ERROR] Method PHPstanIssue::whyDoesThisFail() should return
Illuminate\Support\Collection&iterable<Foo> but returns
Illuminate\Support\Collection&iterable<Illuminate\Support\Collection&iterable<stdClass>>. (PHPstan)
为什么 PHPstan 不能推断出这个管道的正确结果类型?如何让 PHPstan 理解管道?
class MyCodeWorks extends TestCase
{
public function testPipeline()
{
$result = (new PHPstanIssue())->whyDoesThisFail(
new Collection(
[
new Collection([new \stdClass(),new \stdClass()]),new Collection([new \stdClass()]),]
)
);
self::assertCount(3,$result);
foreach ($result as $item) {
self::assertInstanceOf(Foo::class,$item);
}
}
}
会过去的。
就这个问题而言,我的 Foo
只是一个虚拟班级。重要的是它需要一个 stdClass
实例并将其转换为一个 ?Foo
实例。
class Foo
{
public static function get(\stdClass $std): ?Foo
{
// @PHPstan-ignore-next-line
return (bool) $std ? new static() : null;
}
}
解决方法
Illuminate\Support\Collection
类本身不是通用的。所以写 Collection<Foo>
是错误的。这会导致 Illuminate\Support\Collection&iterable<Illuminate\Support\Collection&iterable<stdClass>>
您有两个选择:
-
安装 Larastan。它是 Laravel 的 PHPStan 扩展。它有 stub files 使
Illuminate\Support\Collection
类通用。 -
或者,如果您只是使用
illuminate/collections
独立包而没有完整的 Laravel 应用程序,您可以编写自己的存根文件。 来自PHPStan docs:
...您可以使用正确的 PHPDoc 编写存根文件。它就像源代码,但 PHPStan 只从中读取 PHPDocs。所以命名空间和类/接口/特征/方法/函数名称必须与您描述的原始来源匹配。但是方法体可以留空,PHPStan 只对 PHPDocs 感兴趣。
对于您的示例,以下存根文件应该足够了:
<?php
namespace Illuminate\Support;
/**
* @template TKey
* @template TValue
* @implements \ArrayAccess<TKey,TValue>
* @implements Enumerable<TKey,TValue>
*/
class Collection implements \ArrayAccess,Enumerable
{
/**
* @template TReturn
* @param callable(TValue,TKey): TReturn $callable
* @return static<TKey,TReturn>
*/
public function map($callable) {}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。