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

3

19

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 ?

Ermine answered 24/4, 2020 at 22:15 Comment(3)
Please ask on GitHub next time: github.com/phpstan/phpstan/issues/new/chooseDoggo
@OndřejMirtes I didn't want to bother you on GitHub as it is not a bug, but I'll remember (I often visit your GitHub btw).Ermine
I treat GitHub issues as a support inbox, so it's fine :)Doggo
I
32

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>.

Intyre answered 25/4, 2020 at 8:34 Comment(3)
Thank you. I think I understand, but just to be sure: the int type represents the foreign key type ?Ermine
I'm not sure what Doctrine puts there as the iterable key type, you should try it out.Doggo
Don't forget the space between coma and Slide! I lost one hour because of this space ^^Rabbinical
M
8

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

Middlebrow answered 7/10, 2020 at 11:11 Comment(1)
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 genericsErmine
A
0

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

Ammonic answered 30/7, 2024 at 9:51 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.