# PHP 7.1 and PHPDocs

**URL:** <https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171>\
**Category:** Contributors\
**Created:** [June 26, 2017, 4:31pm UTC](https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171 "2017-06-26T16:31:08Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![michalbundyra](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/michalbundyra/32/185_2.png) [@michalbundyra](https://discourse.laminas.dev/u/michalbundyra)\
**Post date:** [June 26, 2017, 4:31pm UTC](https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171/1 "2017-06-26T16:31:08Z")

</div>

We start discussing PHPDocs in PHP 7.1 project in other topics:  
[https://discourse.zendframework.com/t/feedback-on-problem-details-module/107/13?u=webimpress](https://discourse.zendframework.com/t/feedback-on-problem-details-module/107/13?u=webimpress)  
[https://discourse.zendframework.com/t/component-upgrade-for-php-7-1/28/9](https://discourse.zendframework.com/t/component-upgrade-for-php-7-1/28/9)  
[https://discourse.zendframework.com/t/how-should-we-provide-return-type-declarations-for-fluent-interfaces/30/17](https://discourse.zendframework.com/t/how-should-we-provide-return-type-declarations-for-fluent-interfaces/30/17)

it will be nice to discuss at here as separate issue.

**Why to bother?**

With PHP 7.1 we can use type hinting (also for simple types) and return types defined next to the function. Often PHPDoc comment looks like duplicated information we already provided in method signature. However in PHPDocs we can add much more information and be more specific (for example as @PowerKiKi said: type-hint `array` and PHPDocs `int[]`). In PHPDocs we have to always add `@throws` tags as it is not specified anywhere in method signature (probably we should include all throws, even if it is thrown from other method call inside the function).

**What do you think?**

**Should we always add FULL PHPDocs with `@params`, `@return`, `@throws`… even if it duplicates some information or add only needed PHPDocs part (when something is “different” than in signature)?**

My opinion is that we should keep full PHPDocs, because:

- it will be consistent and clear
- we can use automated tools to sync comments with method signature (phpcs?)
- we can specify more information in PHPDocs, always have everything there, all params, throws and return type
- if we need add description to the variable/return type/throws we add it in PHPDocs. Not always is possible to chose descriptive-enough and short variable/param name.

If we decide to add only PHPDocs tags only when needed I can see following issues:

- if we want to add description to one param should we define all others also in PHPDocs?
- if we want to change type of variable (to be more specific - `int[]`) should we add also all others?
- how IDE/phpdocumentor (if anybody is using it) is gonna work with partial informations in PHPDocs?
- how we make sure that PHPDocs added only when needed is right and it’s not a bug - if we define it only in some functions it would be not clear if it is right that it’s there or its just mistake/residue.
- if we are going to use libraries that supports PHP 5.6/PHP 7.0 there will not be type-hinting/return types. If we implement/extend some interface/class from that library we would be able to add type hinting/return type because of declaration incompatibility. Should we then add only `@inheritDoc`, nothing, or PHPDocs with params/return/throws tags?

What do you think? What do you prefer? Maybe you have another ideas/comments?

---

<div class="post-metadata">

**Author:** ![matthew](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/matthew/32/14_2.png) [@matthew](https://discourse.laminas.dev/u/matthew)\
**Post date:** [June 27, 2017, 4:01pm UTC](https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171/2 "2017-06-27T16:01:36Z")

</div>

I personally prefer to have docblocks only if they provide more information than I can glean from the signature. This would mean:

- Document with `@param` annotations only if the type varies, or if explanation of its purpose and/or value are required. This needs only be done for the specific arguments where this is needed, as the annotation includes the argument name.
- Document with `@return` annotation only if the type varies, or the return value needs an explanation.
- Document with `@throws` ALWAYS when a method explicitly throws one or more exceptions.
- If you can provide a meaningful description detailing the method’s purpose and usage.
- Document with `@inheritDoc` if the _parent_ method’s docblock has additional information.

To answer the last bullet point, we will only be supporting PHP 7.1+ going forward, so the above should largely answer those things.

All of that said: my opinion is largely contingent on how phpDocumentor and IDEs interpret docblocks in these situations. If they do not handle them cleanly, then we should likely be consistent and add them everywhere, and, in such a case, I’d support having a phpcs rule that would detect if they are out of sync (and, better yet, fix them!).

---

<div class="post-metadata">

**Author:** ![cpm](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/cpm/32/107_2.png) [@cpm](https://discourse.laminas.dev/u/cpm)\
**Post date:** [June 27, 2017, 8:42pm UTC](https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171/3 "2017-06-27T20:42:25Z")

</div>

Thats how PhpStorm 2017.1.4 (May 16, 2017) generates docblocks:

```php
    /**
     * @param string $key
     * @param \ArrayObject $container
     * @return string
     * @throws \Exception
     */
    public function methodExample(string $key, \ArrayObject $container): string
    {
        if ($container->count() === 0) {
            throw new \Exception();
        }
        if (!$container->offsetExists($key)) {
            throw new \RuntimeException();
        }
        if (!is_string($value = $container->offsetGet($key))) {
            throw new \LogicException();
        }
        return $value;
    }

```

By default parameters and return type is added to docblock. Mismatch between docblock and method signature is reported as invalid docblock (warning, part of docblock underlined). Runtime and logic exceptions are skipped (default code style).

Personally I like when docblocks are always there, even if something is self-explanatory. That’s also what I would expect from framework like Zend, where we got that “configuration over magic” (I know, it’s not related, but still got that on my mind).

---

<div class="post-metadata">

**Author:** ![matthew](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/matthew/32/14_2.png) [@matthew](https://discourse.laminas.dev/u/matthew)\
**Post date:** [June 27, 2017, 9:23pm UTC](https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171/4 "2017-06-27T21:23:20Z")

</div>

@cpm Question: what does PHPStorm display for typehints for a method you’re calling if that method has PHP 7.1+ typehints and a subset of `@param` annotations?

---

<div class="post-metadata">

**Author:** ![ocramius](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/ocramius/32/23_2.png) [@ocramius](https://discourse.laminas.dev/u/ocramius)\
**Post date:** [June 28, 2017, 3:29am UTC](https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171/5 "2017-06-28T03:29:38Z")

</div>

The behaviour is consistent whether the docblock is there or not: the IDE  
will consider both definitions like with union types if there is a mismatch.

It will also report un-documented `@throws` if any callee has an unhanded  
thrown exception that is documents as `@throws` in the callee.

If it was for me, and we had full PHP 7.1 hints, I would completely drop  
docblocks except for following scenarios:

- @param array (this always requires better specifications)
- Same for iterable/Traversable
- @throws of any sort: if the method throws or rethrows. This may look  
annoying, but is extremely important to eagerly detect BC breaks related to  
thrown exception types. A glimpse at the docblock changes in a patch and  
you know that an added or removed `@throws` is a problem

---

<div class="post-metadata">

**Author:** ![cpm](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/cpm/32/107_2.png) [@cpm](https://discourse.laminas.dev/u/cpm)\
**Post date:** [June 28, 2017, 4:57am UTC](https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171/6 "2017-06-28T04:57:40Z")

</div>

Exactly like that, it creates union if there is mismatch between both definitions (so type hint is like “string|int”)

---

<div class="post-metadata">

**Author:** ![michalbundyra](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/michalbundyra/32/185_2.png) [@michalbundyra](https://discourse.laminas.dev/u/michalbundyra)\
**Post date:** [July 2, 2017, 8:54pm UTC](https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171/7 "2017-07-02T20:54:38Z")

</div>

All about PHPStorm is true, I’d like to highlight some issues:

- by default PHPStorm generates full PHPDocs (always when we type before method `/**` and press “enter” the whole PHPDocs is generated) - does anyone know if we can configure it? I couldn’t find that option.
- by default PHPStorm highlights issues if PHPDocs is not complete/not consistent - when there is missing param declaration, return type, throws or inconsistent types. I just found that it is configurable and it could be disabled to not check PHPDocs at all.

Is anyone using PHPStorm EAP? Are there any changes in case of PHPDoc and PHP7.1?

I’ve tested `phpDocumentor` with full and partial PHPDocs on PHP7.1. Here is repository I’ve created [https://github.com/webimpress/php-docs](https://github.com/webimpress/php-docs) and here is generated documentation for the library:  
[https://webimpress.github.io/php-docs/index.html](https://webimpress.github.io/php-docs/index.html)  
I described everything there, to summarize: `phpDocumentor` does not support PHP 7.1 yet, and because of that there are some issues. Mainly this tool is generating documentation based on PHPDocs, but it also analyze code in some degree (method params). Maybe with PHP 7.1 support it will be changed/improved. Last release (2.9.0) been on the 22nd of May 2016… ☹

I was thinking about partial docs and still I’m not convinced, but now I thinking that it should be possible to write also some sniffs which checks these PHPDocs and say if these are correct or not. We just need to specify all rules, when we can specify annotations and should be fine. But my biggest worry is that with partial documentation we have to look in “two places” to have full picture what is the function, what parameters it accepts and what exceptions it throws. We wouldn’t be able to read all of it from PHPDocs but from PHPDocs and function declaration. So when we look on the function we will create the same in our head what PHPStorm does with suggestion - union between PHPDocs annotations and function declaration. Probably it’s fine in case of small methods, not sure if in all cases it will be good enough.

Regarding `@throws` annotation, IMHO we should always define all `@throws` - doesn’t matter if function throws it explicit or implicit, I mean:

```php
class Test
{
  /**
   * @throws ErrorException
   * @throws RuntimeException
   */
  public function m1(?int $a) : int
  {
    if ($a) {
      throw new ErrorException();
    }

    return $this->m2();
  }

  /**
   * @throws RuntimeException
   */
  public function m2() : int
  {
    throw new RuntimeException();
  }
}

```

@ocramius is that what you meant?

Another question: how we should specify ‘better’ type for `iterable`/`Traversable`? Should it be `iterable<string>` or `string[]`? If we go with first option, then for arrays we should do `array<string>` or `string[]`, or maybe even `array<int, string>` which means “array with integer keys and string values”?  
Currently PHPStorm for `int[]` in suggestion shows type as `\int[]`, for `array<int, int>` suggestion is just `array`.

---

<div class="post-metadata">

**Author:** ![ocramius](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/ocramius/32/23_2.png) [@ocramius](https://discourse.laminas.dev/u/ocramius)\
**Post date:** [July 7, 2017, 12:09pm UTC](https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171/8 "2017-07-07T12:09:37Z")

</div>

I think [https://www.thecodingmachine.com/type-hint-all-the-things/](https://www.thecodingmachine.com/type-hint-all-the-things/)  
clarifies this

Marco Pivetta

[http://twitter.com/Ocramius](http://twitter.com/Ocramius)

[http://ocramius.github.com/](http://ocramius.github.com/)

---

<div class="post-metadata">

**Author:** ![DASPRiD](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/dasprid/32/34_2.png) [@DASPRiD](https://discourse.laminas.dev/u/DASPRiD)\
**Post date:** [September 12, 2017, 2:21am UTC](https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171/9 "2017-09-12T02:21:33Z")

</div>

That’s not that easy. You have to consider that, as soon as you have any kind of dependency you are using, your method can suddenly throw anything (if you don’t have direct control over that dependency).

---

<div class="post-metadata">

**Author:** ![michalbundyra](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/michalbundyra/32/185_2.png) [@michalbundyra](https://discourse.laminas.dev/u/michalbundyra)\
**Post date:** [September 20, 2017, 12:12pm UTC](https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171/10 "2017-09-20T12:12:29Z")

</div>

Yesterday I’ve pushed new sniffs to [ZendCodingStandard](https://github.com/zendframework/zend-coding-standard/pull/1) library with sniffs to check params, return type and throws in function. I’ve started preparing PR, first for `zend-expressive-hal` to check how it works with these sniffs and I have found several issues:

1. `mixed`/`mixed[]` type is sometimes useful, especially in tests, when we have for example:

```php
public function invalidAttributeNames()
{
    return [
        'null' => [null],
        'false' => [false],
        'true' => [true],
        'zero' => [0],
        'int' => [1],
        'zero-float' => [0.0],
        'float' => [1.1],
        'empty-string' => [''],
        'array' => [['attribute']],
        'object' => [(object) ['name' => 'attribute']],
    ];
}

```

I think then we should allow using it.

1. What type we should define for multidimensional arrays, like:

```php
return [
    'foo' => 'bar',
    'id' => 12345678,
    '_links' => [
        'self' => [
            'href' => '/api/foo',
        ],
        'about' => [
            ['href' => '/doc/about'],
            ['href' => '/doc/resources/foo'],
        ],
    ],
    '_embedded' => [
        'bar' => [
            'bar' => 'baz',
            '_links' => [
                'self' => ['href' => '/api/bar'],
            ],
        ],
        'baz' => [
            [
                'baz' => 'bat',
                'id' => 987654,
                '_links' => [
                    'self' => ['href' => '/api/baz/987654'],
                ],
            ],
            [
                'baz' => 'bat',
                'id' => 987653,
                '_links' => [
                    'self' => ['href' => '/api/baz/987653'],
                ],
            ],
        ],
    ],
];

```

In that case `mixed[]` can be a bit confusing (as it is not one-level array). Any ideas? Maybe we should allow just `array`?

1. It is not always possible to specify type for `array`/`iterable`/`\Traversable`, for example:  
[https://github.com/zendframework/zend-hydrator/blob/master/src/ExtractionInterface.php#L18](https://github.com/zendframework/zend-hydrator/blob/master/src/ExtractionInterface.php#L18)

Another example would be from `zend-expressive-hal`:  
[https://github.com/zendframework/zend-expressive-hal/blob/master/src/ResourceGenerator/ExtractCollection.php#L44](https://github.com/zendframework/zend-expressive-hal/blob/master/src/ResourceGenerator/ExtractCollection.php#L44)

These methods are very generic and we can’t provide better specifications.  
I think we shouldn’t force it. Of course it should be allowed to provide better specification, because in some cases it will be possible and useful.

1. Type `Generator` - functions with `yield`, for example:  
[https://github.com/zendframework/zend-expressive-hal/blob/master/test/Metadata/MetadataMapFactoryTest.php#L105-L117](https://github.com/zendframework/zend-expressive-hal/blob/master/test/Metadata/MetadataMapFactoryTest.php#L105-L117)  
It’s kinda similar to `Traversable`, in perfect world we would like to have better specification but I think it is not always possible or pretty hard to do.

2. Tag `@inheritDoc` and `{@inheritDoc}`  
[https://github.com/phpDocumentor/fig-standards/blob/master/proposed/phpdoc.md#61-making-inheritance-explicit-using-the-inheritdoc-tag](https://github.com/phpDocumentor/fig-standards/blob/master/proposed/phpdoc.md#61-making-inheritance-explicit-using-the-inheritdoc-tag)  
The difference is:

- `@inheritDoc` when we inherit everything from parent method and we are not providing anything extra,
- `{@inheritDoc}` - when we inherit everything from parent and we extend description or specify type, more throws etc.  
What do you think, should we allow using both of them? Currently I do not support any of them, and require define params/return type/throws always (only when needed as we agreed), but I can imagine in some cases with inheritance it will be duplicated many times.

1. Arrays with non-integer keys - let say array of strings with strings keys.  
Here: [http://www.icosaedro.it/phplint/phplint2/doc/reference.htm?p=docblocks#literalarrays](http://www.icosaedro.it/phplint/phplint2/doc/reference.htm?p=docblocks#literalarrays)  
is suggested to use `string[string]` (old notation was `array[string]string`). If we go with `string[string]` PHPStorm doesn’t support it at all - and thinks that type is `string` not even `string[]`.  
Of course if keys are integers we should omit `int` in square brackets (as it is default).  
Another notation I’ve seen is: `array(string => string)` (also not supported by PHPStorm).

2. Arrays with mixed values: but only (let say) `int` and `string`:  
[https://github.com/phpDocumentor/fig-standards/blob/master/proposed/phpdoc.md#arrays](https://github.com/phpDocumentor/fig-standards/blob/master/proposed/phpdoc.md#arrays)  
It’s suggested there to use `(int|string)[]`. As I know, many people used `int[]|string[]` in that case, but I think `(int|string)[]` is more accurate - it means (for me) “array which contains ints and strings (at the same time)”, when `int[]|string[]` means “array of ints XOR array of strings”.

3. Generic types:  
[https://github.com/phpDocumentor/fig-standards/blob/master/proposed/phpdoc.md#collections](https://github.com/phpDocumentor/fig-standards/blob/master/proposed/phpdoc.md#collections)  
For example:

```php
/**
 * @param \ArrayObject<string>
 */

```

Should we allow that style of definition?

1. Defining array values:  
[https://github.com/phpDocumentor/fig-standards/blob/master/proposed/phpdoc.md#examples-12](https://github.com/phpDocumentor/fig-standards/blob/master/proposed/phpdoc.md#examples-12)

```php
/**
 * @param array $options {
 * @var bool $required Whether this element is required
 * @var string $label The display name for this element
 * }
 */

```

We do something similar here:

> <https://github.com/zendframework/zend-code/blob/master/src/Generator/InterfaceGenerator.php#L76-L81>

It is not supported by PHPStorm as far as I know.  
Should we implement it or not?

That’s it for now. Please let me know what do you think on each of above points.  
Below I prepared short questionnaire for all above points, hope it will help 😃

* * *

**1. Allow `mixed` / `mixed[]` types**

_Poll ([view on site](https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171/10))_

**2. Multidimensional arrays:**

_Poll ([view on site](https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171/10))_

**3. Do not require better specification for following types:**

_Poll ([view on site](https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171/10))_

**4. Generators (included in point 4)**

- any suggestions?

**5. `@inheritDoc` and `{@inheritDoc}`**

_Poll ([view on site](https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171/10))_

**6. Array with non-integers keys (array of strings with string keys):**

_Poll ([view on site](https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171/10))_

**7. Array with mixed values (int and string only):**

_Poll ([view on site](https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171/10))_

**8. Generic types:**

_Poll ([view on site](https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171/10))_

**9. Defining array values:**

_Poll ([view on site](https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171/10))_

---

<div class="post-metadata">

**Author:** ![matthew](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/matthew/32/14_2.png) [@matthew](https://discourse.laminas.dev/u/matthew)\
**Post date:** [November 2, 2017, 2:28pm UTC](https://discourse.laminas.dev/t/php-7-1-and-phpdocs/171/11 "2017-11-02T14:28:28Z")

</div>

A few quick notes/observations:

- I see 3 and 4 as essentially the same question, particularly with the way you wrote the poll for 3. `Generator` is a valid return type, and while it may not indicate the _items_ available, the main point is that you’re getting an _iterable_ set. If more information is needed, that’s what the docblock is for. When a more specific type is known or expected, rule 8 surrounding collections/generics can kick in.

- 6 and 9 are also related. I’d argue that a `mixed[]` or `string[]` or similar indicates that an array is being returned with values of the specified type(s), while the `{ @var ... }` notation indicates that an associative array is indicated.
