AymDev
AymDev

Reputation: 7609

PHPStan: Property with generic class does not specify its types: TKey, T

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 ?

Upvotes: 20

Views: 29458

Answers (3)

Martijn
Martijn

Reputation: 16123

I ran into the issue that all these didnt work (nor their multi-line version):

/** @var Collection<int, Note> */
/** @var Collection<int, Note> $notes */
/** @var $notes Collection<int, Note> */

My preliminairy conclusion is that in my project (php8+) I dont have an Annotation reader because my whole project is Attribute based.

My Solution:.

  1. I installed this extension:

    composer require --dev php-static-analysis/phpstan-extension
    
  2. Added this to my phpstan.neon:

    includes:
        - vendor/php-static-analysis/phpstan-extension/extension.neon
    
  3. Used it like so:

    #[Type('Collection<int, Note>')]
    private Collection $notes;
    

More docs: https://github.com/php-static-analysis/phpstan-extension

Upvotes: 0

Ondřej Mirtes
Ondřej Mirtes

Reputation: 5671

ArrayCollection has two type variables:

  • The type of the key (TKey)
  • The type of the value (T).

So ArrayCollection<Slide> isn't sufficient, you need something like ArrayCollection<int, Slide>.

Upvotes: 33

Thomas Landauer
Thomas Landauer

Reputation: 8355

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

Upvotes: 8

Related Questions