17

I'm running PHPStan on a Symfony project where I have the following relation in a Doctrine entity:

/**
 * @ORM\OneToMany(targetEntity="App\Entity\Course\Slide", mappedBy="chapter", cascade={"persist"}, orphanRemoval=true)
 * @ORM\OrderBy({"listOrder" = "ASC"})
 *
 * @var ArrayCollection<Slide>
 */
private $slides;

Running analysis with rule level 6 I got the following message about the property (and its getter return type):

Property App\Entity\Course\Chapter::$slides with generic class Doctrine\Common\Collections\ArrayCollection does not specify its types: TKey, T
You can turn this off by setting checkGenericClassInNonGenericObjectType: false in your phpstan.neon.

My edit attempts only confused PHPStan, maybe because I'm not fully understanding generics here. But silencing the message just because I don't get it would be stupid.

What am I supposed to add or change in the PHPDoc ?

AymDev
  • 6,626
  • 4
  • 29
  • 52

2 Answers2

28

ArrayCollection has two type variables: TKey and T. So ArrayCollection<Slide> isn't sufficient, you need something like ArrayCollection<int, Slide>.

Ondřej Mirtes
  • 5,054
  • 25
  • 36
6

It's

/**
 * @var ArrayCollection<int, Slide>
 */

Doing dump() on the parent entity shows that $slides is a 0-indexed array:

0 => App\Entity\Slide
1 => App\Entity\Slide

So it's an int, but not the entity's ID (since it isn't persisted yet).

Here's an in-depth article on generics by Ondřej Mirtes (=author of PhpStan): https://medium.com/@ondrejmirtes/generics-in-php-using-phpdocs-14e7301953

Thomas Landauer
  • 7,857
  • 10
  • 47
  • 99
  • Thank you, I get it now. I have tried to read this post in the past but did not understand, now it clicks ! Going to refactor some code with generics – AymDev Oct 07 '20 at 15:50