Docblocks for Doctrine collections
Asked Answered
S

4

22

Is there a standard way to document the expected class of entities inside a Collection in the docblock comment in a Doctrine project? Something like:

/**
 * @var Collection<User>
 */
protected $users;

Looks like PHPDoc is the de-facto standard for docblock annotations now, but I couldn't find any mention for this use case.

Stipulate answered 3/9, 2011 at 21:47 Comment(1)
This question is almost 10 years ago now. Today the suggestion of the OP works just fine for me, both in PhpStorm as well as for Psalm. Psalm could demand to also add the key type, so typically: Collection<int, User>Recommend
S
6

UPDATE 2022

Doctrine now documents the generic types of Collection with the @template syntax, which is nowadays supported by PhpStorm & static analysis tools (Psalm & PHPStan) at least:

/**
 * @var Collection<int, User>
 */
protected Collection $users;

The old PhpStorm hacky way of documenting this, Collection|User[] is no longer required.

Stipulate answered 27/6, 2022 at 12:10 Comment(2)
This is not working for me when used in a @return annotation (PhpStorm 2022.2.1)Steamy
That solution works for me, even for @return in PhpStorm 2023.2, thank you!Komsomolsk
S
94

Here is a solution that enables you to have autocompletion both on the Collection methods and your objects methods:

/**
 * @param Collection|User[] $users
 */
public function foo($users)
{
    $users-> // autocompletion on Collection methods works

    foreach ($users as $user) {
        $user-> // autocompletion on User methods work
    }
}

It works like a charm in PhpStorm at least.

Some answered 6/2, 2013 at 9:21 Comment(7)
Nice! Now this is solved, the only thing remaining is an actual typeHint for iterable arguments like array and Collection :)Daylong
Although this works in PhpStorm, I see this an invalid type hint, as its saying you could pass in an array of User objects, in which case any collection methods beyond magic iteration would be invalid on.Uproarious
@Uproarious Collection implements ArrayAccess. So you can use the object like an array and it will work, e.g. $users[] = new User().Some
@MatthieuNapoli Right, but that's only one way. Now you're telling your users that they can use an array but the array can't be used like the collection. Array's don't have an isEmpty() method. And even so, the ArrayAccess interface doesn't allow classes to be used in array functions like array_merge().Uproarious
OK I see your point. I indeed wouldn't use this type-hint for a library that will be used by other users. But for our team, it just works. With the PSR-5 it will be possible to use the generics notation, so that's be more appropriate: Collection<User>. However I'm not sure it will be easy for PhpStorm to handle it.Some
@MatthieuNapoli Yea, agreed. For an internal project, it makes sense, but for an open-source library I wouldn't do this. PhpStorm is exhibiting a strange behavior here. I guess we'll just have to wait for PSR-5 before there's a common specified way of denoting this. :/Uproarious
@MatthieuNapoli PSR-5 is abandoned (php-fig.org/psr) therefore the solution above is the way to goTownley
S
6

UPDATE 2022

Doctrine now documents the generic types of Collection with the @template syntax, which is nowadays supported by PhpStorm & static analysis tools (Psalm & PHPStan) at least:

/**
 * @var Collection<int, User>
 */
protected Collection $users;

The old PhpStorm hacky way of documenting this, Collection|User[] is no longer required.

Stipulate answered 27/6, 2022 at 12:10 Comment(2)
This is not working for me when used in a @return annotation (PhpStorm 2022.2.1)Steamy
That solution works for me, even for @return in PhpStorm 2023.2, thank you!Komsomolsk
W
1

I think User[] should work. Don't remember where I found that.

Woodwaxen answered 4/9, 2011 at 12:40 Comment(1)
I've encountered that somewhere as well, to represent an array of. Doesn't enforce the class of the Collection itself, though!Stipulate
E
0

There are a few different ways to document expected variables. Have a look at the phpDoc documentation for a full list of available tags.

class MyClass
{
    /**
     * Users collection
     * @var \Doctrine\ORM\ArrayCollection
     */
    protected $users;

    /**
     * My method that doesn't do much
     * @param \Doctrine\ORM\ArrayCollection $users
     * @return void
     */
    public function myMethod(\Doctrine\ORM\ArrayCollection $users)
    {
        /** @var \Entities\Users $user */
        $user = current($this->users);
    }
}
Exclaim answered 4/9, 2011 at 12:56 Comment(5)
I was hoping something more explicit and less repetitive would be available... If you have several methods involving $this->users, that means a lot of docblock duplication!Stipulate
ArrayCollection is a generic collection which can take any type of entity (or any object for that matter); and because it can contain anything, autocompletion for collection entities can't work. The third way should work perfectly fine, you just need to check before you use it that it isn't falseExclaim
Also, if you're reusing $this->users, having the docblock at protected $users; deceleration is enough. On another note, your docblocks should explain exactly what you expect. If you have to repeat @param \Doctrine\ORM\ArrayCollection $users for multiple methods, so be it.Exclaim
Thanks, by the way, is it mandatory to explicitely use the @param docblock when using type hinting? I thought that both IDEs and PHPDoc would handle that, and that @param was more intended for primitives now that class/interface type hinting is built in the language.Stipulate
It isn't needed for type hinting in IDEs, but like I said before; you should document everything. Incorrect documentation is just as bad, if not worse than no documentation at all.Exclaim

© 2022 - 2024 — McMap. All rights reserved.