Skip to content

Instantly share code, notes, and snippets.

@mvriel
Created October 2, 2012 20:14
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mvriel/3823010 to your computer and use it in GitHub Desktop.
Save mvriel/3823010 to your computer and use it in GitHub Desktop.
Generic notation in PHPDoc vs. plain array notation
<?php
/**
* @template <T> The type of the individual elements
*/
class ArrayCollection implements IteratorAggregate
{
private $elements;
/**
* @param array<T> $elements
*/
public function __construct(array $elements)
{
$this->elements = $elements;
}
/**
* @return Iterator<T>
*/
public function getIterator()
{
return new ArrayIterator($this->elements);
}
}
// usage
/** @type ArrayCollection<Foo> $col */
$col = new ArrayCollection();
foreach ($col as $elem) {
// $elem is instance of Foo here
}
?>
<?php
class ArrayCollection implements IteratorAggregate
{
private $elements;
/**
* @param mixed[] $elements
*/
public function __construct(array $elements)
{
$this->elements = $elements;
}
/**
* @return ArrayIterator
*/
public function getIterator()
{
return new ArrayIterator($this->elements);
}
}
// usage
/** @type ArrayCollection|Foo[] $col */
$col = new ArrayCollection();
foreach ($col as $elem) {
// $elem is instance of Foo here
}
?>
@moufmouf
Copy link

moufmouf commented Oct 9, 2012

Here is a sample that might make more sense regarding Johannes proposal:

Let's have a look at the SplObjectStorage class, that provides a map where keys can be objects. (http://www.php.net/manual/en/class.splobjectstorage.php)

/** @type SplObjectStorage<MyKeyObject, MyValueObject> */
$splObjectStorage = new SplObjectStorage();

// No need to cast $current into a MyKeyObject
$current = $splObjectStorage->current();

// No need to cast $object into a MyValueObject
$object = $splObjectStorage->offsetGet($key);

I like Johannes proposal because I find it very powerful.
However, let's admit that 90% of the time, we are dealing with arrays, not ArrayCollection or SplObjectStorage, so we should be sure that the use of the @type annotation with the array is rock solid.
For this matter, one thing we do not capture is the difference between an indexed array and a hashmap. PHP does not make any difference between those 2 constructs, and yet, they are completely different and the documentation should tell the user whether the array is numerically indexed, or is a map.

A proposal would be to use 2 keys. For instance:

/** @type array<int, Object> A numerically indexed array of Objects */
$arr1 = array();

/** @type array<string, Object> A map of Objects */
$arr2 = array();

Now, this seems to be a bit of an overkill compared to the more simple proposal from Mike...
In an ideal world, we should also be able to write:

/** @type array<Object> An array of Objects (we don't know about the key) */

But that would not suit well with the @template annotation....
So I'm a bit at a loss here... Any idea on how to make this both powerful and simple to use?

@schmittjoh
Copy link

I see no problem with supporting:

@type array<object> a list of objects, we don't care about the type
@type array<string,object> a map of strings to objects

The @template proposals is not directly related to arrays and more about allowing to write generic classes in userland while still getting the best autocompletion/static analysis that is possible, and btw, you could have more than one @template annotation on your class if your class needs to fill in more holes (like key, and value in a map as in your \SplObjectStorage example).

@mvriel
Copy link
Author

mvriel commented Oct 11, 2012

I wanted to post here that I have not abandoned the discussion but I have been at PHPNW12 the past weekend and am still catching up. A proper response follows somewhere in the upcoming week

@ashnazg
Copy link

ashnazg commented Apr 22, 2013

Could these ideas be successfully condensed into just this one syntax:

@type (class name or primitive type 'array')<(optional key type, ) (required member type) (description)

@mvriel
Copy link
Author

mvriel commented Apr 22, 2013

I have been thinking quite a bit about this proposal in the past time and to be honest, it is starting to grow on me. Though I am not so sure about the @template tag since that would only serve a purpose for a Collection object that only intends to be used with a specific set of values (that and I don't think the name @template is intuitive).

Some concerns that I still have:

  • How to deal with generics where the value may be of several types? Use the or operator (|) as has been done so far?
  • We should also support multi-dimensional notations

@Deltachaos
Copy link

I think we sould keep the or operator for working with several types. But what do you mean by "multi-dimensional notations"?

@cmrafifar
Copy link

Coming from a Java perspective, I would love some kind of Generics support in PHP and/or PHPDOC. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment