Given my class
<?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>
}
}
I am highely confused why phpstan (0.12.64) would fail with:
18: [ERROR] Method PhpstanIssue::whyDoesThisFail() should return
Illuminate\Support\Collection&iterable<Foo> but returns
Illuminate\Support\Collection&iterable<Illuminate\Support\Collection&iterable<stdClass>>. (phpstan)
Why can't phpstan infer the proper result type of this pipe? How can I make phpstan understand the pipe?
I can verify that my code works within a phpunit testcase:
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);
}
}
}
will pass.
My Foo is just a dummy class for the sake of this question. It's only relevant that it takes a stdClass instance and transforms it into a ?Foo one.
class Foo
{
public static function get(\stdClass $std): ?Foo
{
// @phpstan-ignore-next-line
return (bool) $std ? new static() : null;
}
}
Illuminate\Support\Collectionclass is not generic on its own. So writingCollection<Foo>is wrong. That causes the error messages likeIlluminate\Support\Collection&iterable<Illuminate\Support\Collection&iterable<stdClass>>You have two options:
Installing Larastan. It's a PHPStan extension for Laravel. And it has stub files that makes
Illuminate\Support\Collectionclass generic.Or if you are just using the
illuminate/collectionsstandalone package without full Laravel app you can write your own stub files. From PHPStan docs:For your example the following stub file should be enough: