21

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.

Matthieu Napoli
  • 42,736
  • 37
  • 154
  • 239
BenMorel
  • 30,280
  • 40
  • 163
  • 285
  • 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` – 7ochem Jan 07 '21 at 14:12

3 Answers3

93

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.

Matthieu Napoli
  • 42,736
  • 37
  • 154
  • 239
  • 1
    Nice! Now this is solved, the only thing remaining is an actual typeHint for iterable arguments like array and Collection :) – Robbert van den Bogerd Feb 25 '14 at 20:01
  • 2
    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. – Rican7 Oct 23 '14 at 13:00
  • 1
    @Rican7 `Collection` implements `ArrayAccess`. So you can use the object like an array and it will work, e.g. `$users[] = new User()`. – Matthieu Napoli Oct 23 '14 at 20:04
  • @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()`. – Rican7 Oct 23 '14 at 21:04
  • 7
    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`. However I'm not sure it will be easy for PhpStorm to handle it. – Matthieu Napoli Oct 24 '14 at 01:23
  • @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. :/ – Rican7 Oct 24 '14 at 02:27
  • @MatthieuNapoli PSR-5 is abandoned (https://www.php-fig.org/psr/) therefore the solution above is the way to go – Nickolaus Jun 20 '18 at 17:48
1

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

BenMorel
  • 30,280
  • 40
  • 163
  • 285
Maxence
  • 12,184
  • 4
  • 48
  • 66
  • 2
    I've encountered that somewhere as well, to represent an *array of*. Doesn't enforce the class of the Collection itself, though! – BenMorel Sep 04 '11 at 13:28
1

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);
    }
}
adlawson
  • 6,035
  • 1
  • 32
  • 46
  • 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! – BenMorel Sep 04 '11 at 13:36
  • `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 false – adlawson Sep 04 '11 at 13:39
  • 1
    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. – adlawson Sep 04 '11 at 13:41
  • 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. – BenMorel Sep 04 '11 at 14:06
  • 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. – adlawson Sep 04 '11 at 14:22