鉴于我的课
<?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 理解管道?
我可以验证我的代码在 phpunit 测试用例中是否有效:
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;
}
}