Should PhpStorm complete in foreach?
PhpStorm 2021.2 support for generics in PHP. But when I use foreach above collection PhpStomr does not recognize correct element type.
Should PhpStorm autocomplete inner types in foreach?
It is important when I want to change method names.
Example code
use Ramsey\Collection\AbstractCollection;
/**
* @extends AbstractCollection<Specific>
*/
class SpecificCollection extends AbstractCollection
{
public function getType(): string
{
return Specific::class;
}
}
class Specific
{
public function __construct(private string $code)
{}
public function getCode(): string
{
return $this->code;
}
}
class Test {
public function test1(): void
{
$collection = new SpecificCollection([new Specific('code1')]);
foreach ($collection as $item) {
$item->getCode(); // IDE do not recognize
}
}
/**
* @param SpecificCollection<Specific> $collection
*/
public function test2(SpecificCollection $collection): void
{
foreach ($collection as $item) {
$item->getCode(); // IDE do not recognize
}
}
/**
* @param SpecificCollection<Specific>|array<Specific> $collection
*/
public function test3(SpecificCollection $collection): void
{
foreach ($collection as $item) {
$item->getCode(); // IDE do not recognize
}
}
public function test4(SpecificCollection $collection): void
{
foreach ($collection as $item) {
/** @var Specific $item */
$item->getCode(); // Only this IDE recognize
}
}
public function test5(SpecificCollection $collection): void
{
foreach ($collection as $item) {
\assert($item instanceof Specific);
$item->getCode(); // Only this IDE recognize
}
}
}
Thanks for calling attention to this!
The support for generics in PhpStorm is limited right now, but it looks like they added support for this in 2021.2.1 (see the release notes here; it's the note "Support inference based on IteratorAggregate<User>"). I just upgraded to 2021.2.2 to see if I can get this to work.
It works when I change SpecificCollection to the following:
/**
* @extends AbstractCollection<Specific>
* @implements IteratorAggregate<Specific>
*/
class SpecificCollection extends AbstractCollection implements IteratorAggregate
{
public function getType(): string
{
return Specific::class;
}
}
However, this should work without making this change because Ramsey\Collection\ArrayInterface uses the annotation @extends IteratorAggregate<array-key, T>, but it seems PhpStorm isn't picking this up, or maybe I have something incorrect in the annotations.
I'll do some more digging around to see if I can figure out whether I need to change something in the library or whether this is a limitation in PhpStorm.
PhpStorm 2021.3 has the same issue.
Adding @implements \IteratorAggregate<array-key, T> directly on AbstractCollection doesn't change anything, and neither does using @implements \IteratorAggregate<Specific>. It looks like @implements \IteratorAggregate<ClassName> only works on the concrete class, not the abstract.
I'm fairly sure this is a PhpStorm limitation and relates to these issues:
- https://youtrack.jetbrains.com/issue/WI-63612
- https://youtrack.jetbrains.com/issue/WI-63261
It looks like this is now working in PhpStorm, especially after I did an audit of all the type annotations and updated them in version 2.0.0. I'm closing this issue now, but if you still have problems, let me know.