Proper phpdoc comment for iteratable object?
Asked Answered
S

4

12

I'm having a bit of a problem trying to get a correct autocompletion for the following code example. I'm using PHPStorm 7 on a Win7 machine.

First just a simple class.

/**
 * Class myObject
 */
class myObject
{
    /**
     * some method
     */
    public function myMethod()
    {
        // do something
    }
}

This one is the collection class which can contain multiple instances of the prior class and implements the IteratorAggregate interface.

/**
 * Class myCollection
 */
class myCollection implements IteratorAggregate
{
    /**
     * @var myObject[]
     */
    protected $_objects = array();


    /**
     * @param myObject $object
     * @return myCollection
     */
    public function add(myObject $object)
    {
        $this->_objects[] = $object;

        return $this;
    }


    /**
     * @return ArrayIterator
     */
    public function getIterator()
    {
        return new ArrayIterator($this->_objects);
    }
}

And here is the code example.

$collection = new myCollection;

$collection->add(new myObject);
$collection->add(new myObject);

foreach ($collection as $object) {
    $object->myMethod(); // gets no autocompletion
}

As you may have guessed (and read in the example) the myMethod() call gets not autocompleted and is beeing listed in the code analysis. The only way i found is adding a comment block for $object, which i find, to be honest, extremely annoying.

/** @var $object myObject */
foreach ($collection as $object) {
    $object->myMethod(); // gets autocompletion now, but sucks
}

So, any ideas or fundamented knowledge on how to solve this?

Silin answered 8/3, 2014 at 17:0 Comment(1)
Maybe it is because ArrayIterator's return value is mixed but I'm not sure if PHPStorm can handle values of iterations. Try to create an own Iterator which returns your object or interface ans see if the IDE can handle this. At the end trying an own Iterator is maybe an overhead for the project so maybe @var should be ok.Idette
N
11
/**
 * @return ArrayIterator|myObject[]
 */
public function getIterator()
{
    return new ArrayIterator($this->_objects);
}

For extended classes (the base class is above):

/**
 * @method myObject[] getIterator()
 */
class ExtendedClass extends BaseCollection
{
}

or

/**
 * @method iterable<myObject> getIterator()
 */
class ExtendedClass extends BaseCollection
{
}

I think this will be best way to handle such case. at least it works with PHPStorm

Nesta answered 21/1, 2020 at 8:26 Comment(0)
I
1

Your

/** @var $object myObject */

block is indeed the correct way to accomplish this. The syntax you are expecting to do the work,

/** * @var myObject[] */

is not standard phpdoc notation, although it is in informal use and has some effort ongoing to standardize. Until such standardization does happen, IDEs recognizing it will probably be hit-or-miss. IDE coverage of your $object local var block is also hit-or-miss, actually.

Ieshaieso answered 18/3, 2014 at 15:17 Comment(1)
I think @var MyObject[] is standard notation now, circa 2022. Per docs.phpdoc.org/guide/guides/types.html#arrays Moreso, using iterable<MyObject> can be more generic, if the caller doesnt need to have index-based access to the dataIhab
R
1

In your myCollection class, override current() as follows:

/** @return myObject */
public function current() {
    return parent::current();
}
Rusticus answered 30/5, 2017 at 15:42 Comment(0)
O
0

Possible workaround (also ugly) is to create static "constructor", that will return myObject. At least it works in eclipse. If you want to see collection methods too, then just add myCollection to return as "@return myObject[]|myCollection"

class myCollection implements \IteratorAggregate
{
    /**
     * @return myObject[]
     */
    public function create()
    {
        return new static();
    }
}
Octosyllable answered 1/11, 2016 at 18:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.