[PSR-5] Hash/associative array notation

3,003 views
Skip to first unread message

Mike van Riel

unread,
Oct 16, 2014, 3:27:37 PM10/16/14
to php...@googlegroups.com
Dear all,

A feature in PHPDoc that has been considered to be missing by several users is the ability to document the contents of associative arrays. This feature is, for example, desired to document option arrays, json_decoded output and similar structures.
Note: Please do not discuss the validity of passing information using an array versus an object. The basic premise is that this is a desired piece of functionality.
In the current draft I have written a proposal where you can use brackets with a tag to indicate that there is more to that tag's contents than is described by the type alone. I have named this construct an `Inline PHPDoc` because syntactically it is a recursive repetition of a PHPDoc block. When combined with the `array` type it describes the contents of an associative array, or hash, and when combined with an `object` type it describes a class without declared members.

Here is an example:

/**
 * Initializes this class with the given options.
 *
 * @param array $options {
 *     This is a description should you wish to add it.
 *
 *     @type boolean $required Whether this element is required
 *     @type string  $label    The display name for this element
 * }
 */
public function __construct(array $options = array())
{
    <...>
}
In the example above we demonstrate a constructor with (a contrived) example of a summary together with a single options array that is expected to contain two elements: required and label.

In the example above we still use the `@type` tag but since recently I have reverted the suggestion to use @type instead of @var because it causes to many head aches.

I would like to ask for your opinion on

- this notation
- which tag to use for hashes (for objects @property and @method work nicely)
- how to indicate required or optional members
- whether or not to prefix the member name with a dollar; I introduced this to be consistent with other uses of @var/@type and to distinguish between a type and a member name

All input is greatly appreciated as I want to be able to write a permanent addition to the specification on this subject that has consensus.

Thank you for your input,

Mike

Dracony

unread,
Oct 16, 2014, 3:33:10 PM10/16/14
to php...@googlegroups.com
Looks really nice. What would be also awesome is to be able to document array key and value types. Perhaps this could be added to your idea by having things like @key and @value for arrays?
I think everybody who was waiting for PHP to implement typehinted collections would really welcome this feature

Aaron Scherer

unread,
Oct 16, 2014, 3:41:18 PM10/16/14
to php...@googlegroups.com
- this notation

Love it.
 
- which tag to use for hashes (for objects @property and @method work nicely)

as opposed to @type? I'm a fan of @type or @param
 
- how to indicate required or optional members

hmmm. maybe "required" before the type
 
- whether or not to prefix the member name with a dollar; I introduced this to be consistent with other uses of @var/@type and to distinguish between a type and a member name
 
I'd think no...

Bernhard Schussek

unread,
Oct 16, 2014, 3:43:44 PM10/16/14
to php...@googlegroups.com
Hi Mike,

Thank you for your efforts!

2014-10-16 21:27 GMT+02:00 Mike van Riel <draco...@gmail.com>:
I would like to ask for your opinion on

- this notation

Looks good! Another one to consider (and probably you have already considered it) is:

/**
 * @param array   $options           Additional options
 * @param boolean $options[required] Whether this element is required 
 * @param string  $options[label]    The display name for this element
 */

More repetitive, but intuitive IMO. In the end both formats work for me.
 
- how to indicate required or optional members

Question mark? Do we have similar functionality anywhere else in the PSR?

@type boolean required? Whether this element is required. Default: false

We could also add support for default values and replace the question mark by =

@type boolean required=false Whether this element is required

- whether or not to prefix the member name with a dollar

I would not. The member name might actually start with a dollar.

Cheers,
Bernhard

Alexander Makarov

unread,
Oct 16, 2014, 3:56:29 PM10/16/14
to php...@googlegroups.com
- Notation is OK. Quite intuitive.
- We're describing key-value pair. So my suggestion is @key Type $keyName. @type is OK as well but less explicit.
- Could use PHP notation i.e. @type boolean $required = false Description of the key-value pair.
- I'm for consistency even if keys aren't variables.

ɹǝɹǝɥɔs uoɹɐɐ

unread,
Oct 16, 2014, 4:00:00 PM10/16/14
to php...@googlegroups.com
I think Mike was asking how you define a KEY as required.

@type required boolean required=false Whether this element is required

So, the 'required' element of the $options array is required, and defaulted to false, in this example.

A. Scherer

--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/3dbe1d5f-0965-4c14-8133-60ef231247ce%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Mike van Riel

unread,
Oct 16, 2014, 4:03:04 PM10/16/14
to php...@googlegroups.com
Well, actually the entire element is either required or not :) Can't have a key without a value and vice versa :)

Dracony

unread,
Oct 16, 2014, 4:03:51 PM10/16/14
to php...@googlegroups.com
Isn't a key always present in an array anyway =) ? Maybe you mean defining a key as a mandatory string ?

Drew Jaynes

unread,
Oct 16, 2014, 4:04:49 PM10/16/14
to php...@googlegroups.com
Hi folks, outsider checking in.

- this notation

Yes!

- which tag to use for hashes (for objects @property and @method work nicely)

I agree with Alexander that @key might be more fitting, though it could create confusion if this is multi-purpose for arrays and objects. Other than that, I think @type works well here, but if that's too generic, perhaps specializing @param (see 5.3.2) might be useful instead, something like @param:type nested under @param would suffice.
 
- how to indicate required or optional members

I think prefacing the description might be the cleanest way to approach it. If it's marked optional, it's optional, if it's not, it's required. Seems pretty straightforward. Really what I think it comes down to is trying to find parity in line structure what you'd expect from @param especially as this is a nested hash, that is to say: @type type $key Description

- whether or not to prefix the member name with a dollar; I introduced this to be consistent with other uses of @var/@type and to distinguish between a type and a member name

It was my understanding the $ prefix was proposed as an easement for parsing. I think it at glance it's a lot easier to grok a line if the $ stays.
 

Drew Jaynes

unread,
Oct 16, 2014, 4:08:54 PM10/16/14
to php...@googlegroups.com
I agree with Alexander that @key might be more fitting, though it could create confusion if this is multi-purpose for arrays and objects.

 Sorry, glossed right over "(for objects @property and @method work nicely)". @key might work.

Mike van Riel

unread,
Oct 16, 2014, 4:27:41 PM10/16/14
to php...@googlegroups.com
I am not sure I follow the train of thought in this part of the thread.

Aaron and Dracony: can you post examples of what you are thinking of?

ɹǝɹǝɥɔs uoɹɐɐ

unread,
Oct 16, 2014, 4:32:19 PM10/16/14
to php...@googlegroups.com
I guess i was thinking about optional parameters of both an array, and a parameter

/**
 * @type string $foo Some foo thingy
 * @type array $bar {
 *         Some description about $bar
 *
 *          @key string foo-item Some item in the $bar array
 *          @key optional bool baz  Some optional item in the $bar array
 * }
 * @type optional string|null $baz BAZ!
 *
 */
public function foo($foo, array $bar, $baz = null);

A. Scherer

Stefano Torresi

unread,
Oct 16, 2014, 5:38:36 PM10/16/14
to php...@googlegroups.com
I like the feature, but I don't quite dig the proposed notation.
IMHO it's not immediately clear about the fact that it describes an associative array instead of a indexed one (even if the latter is not the use case for the notation, that's beside my point). I think the dollar notation and the ambiguity of the @type tag contributes to this feeling. Especially the dollar, I find its semantic not very transparent and potentially confusing.

I would personally prefer the key names to be enclosed with quotes, as they usually appear in the code.

About the tag, since it's actually describing a value, and not a key, using @key or something like that is out of the question. Maybe @value, since "@type string" and "@type integer" happen to be also valid key annotations, and that would be ambiguous.
I don't think any tag is required to describe the key. Either it's a string or it's an integer, but they can all be assumed as strings because numbers will be type casted.
Ultimately, what matters is the semantic of the array values.

For the required annotation, I honestly don't know, using the description arbitrarily seems the most readable thing.

Bottom line, I would rather like something like this...

/**
 * @param array $options {
 *     @value boolean 'foo' (REQUIRED) Description lorem ipsum dolor
 *     @value string  'bar' Description lorem ipsum dolor
 * }
 */

It comes down very much to personal taste, though.

Anyway thank you, and keep up the good work.


Stefano Torresi

Dracony

unread,
Oct 16, 2014, 5:59:46 PM10/16/14
to php...@googlegroups.com
Actually I just had an awesome idea! The bestest even!
Examples:

/**
 * 
 * @param array $map {
 *    @type   map 
 *    @key    string
 *    @value integer
 *}   This would define a hash with string keys and integer values
 */

/**
 * 
 * @param array $map {
 *    @type   list
 *    @value integer
 *}   This would define a 0-indexed array of values
 */

/**
 * 
 * @param array $map {
 *    @type   document
 *    @field   string  username 
 *    @field {
 *          @required
 *          @type string
 *          @key id
 *     }
 *}   This would define a document with optional username field and a required id field
 */


On Thursday, October 16, 2014 9:27:37 PM UTC+2, Mike van Riel wrote:

John Patrick Gerdeman

unread,
Oct 17, 2014, 12:47:48 AM10/17/14
to php...@googlegroups.com

>>/**
>> *
>> * @param array $map {
>> * @type map
>> * @key string
>> * @value integer
>> *} This would define a hash with >>string keys and integer values
>> */

I then would know it's a hash. 5 lines of comments seem very much for such limited Information.

>>/**
>> *
>> * @param array $map {
>> * @type list
>> * @value integer
>> *} This would define a 0-indexed >>array of values
>> */

Isn't this the same as
@param int


Mike,

would it be possible to nest this notation?

/**
* Initializes this class with the given options.
*
* @param array $options {
* This is a description should you wish to add it.
*
* @type boolean $required Whether this element is required
* @type string $label The display name for this element

* @type array[] $fieldSet {
* @type string $name
* @type string $ baz
* }


* }
*/
public function __construct(array $options = array())
{
<...>
}

How could this definition be reused? (This requirement has been discussed before, I believe. Ultimately discarded because this added another set of headaches. Where to put it? Should namespaces be used? If so, please ignore.)

Mike van Riel

unread,
Oct 17, 2014, 2:14:45 AM10/17/14
to php...@googlegroups.com
Hi Stefano,

See my responses inline:

On 16-10-14 23:38, Stefano Torresi wrote:
I like the feature, but I don't quite dig the proposed notation.
IMHO it's not immediately clear about the fact that it describes an associative array instead of a indexed one (even if the latter is not the use case for the notation, that's beside my point). I think the dollar notation and the ambiguity of the @type tag contributes to this feeling. Especially the dollar, I find its semantic not very transparent and potentially confusing.
One thing I would like to note is that it need not be limited to associative arrays but it is the main focus.


/**
 * @param array $options {
 *     @value boolean '0' Description lorem ipsum dolor
 *     @type boolean $1 Description lorem ipsum dolor
 
* }

 */

Would also perfectly describe a numeric array :)
(used your suggested notation and the original proposal for comparison purposes)


I would personally prefer the key names to be enclosed with quotes, as they usually appear in the code.
That is an interesting suggestion that I had not considered yet. Thank you for that.

About the tag, since it's actually describing a value, and not a key, using @key or something like that is out of the question. Maybe @value, since "@type string" and "@type integer" happen to be also valid key annotations, and that would be ambiguous.
I don't think any tag is required to describe the key. Either it's a string or it's an integer, but they can all be assumed as strings because numbers will be type casted.
Ultimately, what matters is the semantic of the array values.
I agree with this, the type of the key can be derived from the name used in the @type/@value tag and if you really insist you can use the following notation:

/**
 * @param array<integer,boolean> $options {
 *     @value boolean '0' Description lorem ipsum dolor
 *     @type boolean $1 Description lorem ipsum dolor
 
* }

 */

(which is also new but that is another discussion ;))


For the required annotation, I honestly don't know, using the description arbitrarily seems the most readable thing.

Bottom line, I would rather like something like this...

/**
 * @param array $options {
 *     @value boolean 'foo' (REQUIRED) Description lorem ipsum dolor
 *     @value string  'bar' Description lorem ipsum dolor
 * }
 */
I am going to make a summary of the suggested ways to mark an element as required or option and follow up in a separate post. I will include this one as well.


It comes down very much to personal taste, though.

Anyway thank you, and keep up the good work.
Thank you!

Mike van Riel

unread,
Oct 17, 2014, 2:24:55 AM10/17/14
to php...@googlegroups.com
Hi Dracony,

Defining what you call a map and list are covered using the new Collection notation:

/**
 * @param array<string,integer> $map
 */

/**
 * @param array<integer, integer> $list
 * @param array<integer> $anotherList
 */

This proposal is specific to what you call a Document.

The suggestion that you have made for, what you call, Document is quite verbose and the notation changes as soon as a required indicator is needed? Do I understand this correctly?
--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.

Mike van Riel

unread,
Oct 17, 2014, 2:30:19 AM10/17/14
to php...@googlegroups.com
Hi John Patrick,

I believe it should be nestable. I would try to avoid writing code that
actually does this but I can imagine the realworld use case :)

I think that your mentioned notation is spot-on for nesting arrays.

/**
* Initializes this class with the given options.
*
* @param array $options {
* This is a description should you wish to add it.
*
* @type boolean $required Whether this element is required
* @type string $label The display name for this element
* @type array[] $fieldSet {
* @type string $name
* @type string $ baz
* }
* }
*/


Regarding re-using the notation: there is a though floating in my head
for introducing an @struct tag but I would really like to discuss that
separately to limit the scope of this conversation.

Chuck Burgess

unread,
Oct 17, 2014, 11:39:58 AM10/17/14
to php...@googlegroups.com
I'm inclined toward the `keyText` format, since it is exactly that given Key string that we document via one @var line:

/**
 * Short Description
 *
 * Long Description foo bar baz,
 * foosum barsum bazsum,
 * fee figh foh fum.

 *
 * @param array $options {
 *     Description for $options itself goes here.
 *
 *     @var bool   'required' the value here should be a bool flag
 *     @var string 'label'    the value here should be a string

 * }
 */
public function __construct(array $options = array()) {}

Functionally speaking, is there any other One True Identifier for that given member of the array?  If we formalize a syntax for this identifier, it seems to me that the actual string that is the member's Key is the proper identifier.

Regarding required vs optional members of an array, what do we want to accomplish by building a syntax for it?  Does it influence IDE autocomplete behavior in some way?  Should the documentation somehow link to something else based on that identifier?  I'm not yet convinced this one aspect of info justifies a syntax of its own, since that info can be conveyed in the @var's text description already.

In the case of an inline doc for an object (that presumably is not itself already a declared class, and thus has its own docs elsewhere), I agree that @property is valid for things like \stdClass->prop1, and would be written as "@var bool $prop1 here is description".  However, is it even feasible that an undeclared method can exist on \stdClass?  Maybe I'm missing something here.
--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+unsubscribe@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.

Mike van Riel

unread,
Oct 17, 2014, 11:44:08 AM10/17/14
to php...@googlegroups.com
I need to be brief due to time constraints, my apologies


On 17-10-14 17:39, Chuck Burgess wrote:
I'm inclined toward the `keyText` format, since it is exactly that given Key string that we document via one @var line:

/**
 * Short Description
 *
 * Long Description foo bar baz,
 * foosum barsum bazsum,
 * fee figh foh fum.
 *
 * @param array $options {
 *     Description for $options itself goes here.
 *
 *     @var bool   'required' the value here should be a bool flag
 *     @var string 'label'    the value here should be a string
 * }
 */
public function __construct(array $options = array()) {}

Functionally speaking, is there any other One True Identifier for that given member of the array?  If we formalize a syntax for this identifier, it seems to me that the actual string that is the member's Key is the proper identifier.
Yes, the actual key of the hash is unique in an array and should be the identifier in the hash syntax.


Regarding required vs optional members of an array, what do we want to accomplish by building a syntax for it?  Does it influence IDE autocomplete behavior in some way?  Should the documentation somehow link to something else based on that identifier?  I'm not yet convinced this one aspect of info justifies a syntax of its own, since that info can be conveyed in the @var's text description already.
Use case: It could help tools with inferring whether too little information was passed to a method or function


In the case of an inline doc for an object (that presumably is not itself already a declared class, and thus has its own docs elsewhere), I agree that @property is valid for things like \stdClass->prop1, and would be written as "@var bool $prop1 here is description".  However, is it even feasible that an undeclared method can exist on \stdClass?  Maybe I'm missing something here.
Don't you mean `@property bool $prop1 here is a description`?

And using @method can be used to augment an existing class in case it provides insufficient @method calls and has magic methods. I have encountered this with Predis for example.

To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/5440B777.9010404%40gmail.com.

For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.

John Flatness

unread,
Oct 17, 2014, 9:37:25 PM10/17/14
to php...@googlegroups.com
I think having the key name quote-enclosed rather than dollar-sign-prefixed is the superior option, both because it maintains consistency with the actual PHP syntax and also because it lets you more easily support for keys that otherwise probably wouldn't parse so well:

@type string "this key has spaces" Then here's some description

I haven't seen it mentioned, but as another alternative for declaring required members would just be a separate tag, especially if you're already introducing one for keys/values generally: @value and @requiredValue (or @value and @optionalValue, reversing the default semantics of @value). This would presumably avoid any parsing or ambiguity issues, but at the cost of cluttering the set of tags somewhat.

As an aside, I also think the notation Bernard Schussek proposed is promising. It would allow you to use the "real" syntax for both string and integer keys, uses only existing tags, and would let you nest arbitrarily deep. It also seems like it would be simpler to parse, as it's just "standard" tags and the consumers would only need to specially handle param/var/type tags that had brackets in the variable name.

Maksim Kochkin

unread,
Oct 18, 2014, 3:15:23 AM10/18/14
to php...@googlegroups.com
Hi Mike. Thanks for the really wanted feature proposal.

My thoughts on it
- quoted keys
- '?' sign for optional keys (not required), before or after
- type of a key before type of a value separated with ':' (string by default) for those cases when keys have different types
- any new name for tag describing item (@key, @value, @item — all are ok), but not existing, cause there is new syntax here

/**
 * Initializes this class with the given options.
 *
 * @param array $options {
 *     This is a description should you wish to add it.
 *
 *     @item boolean 'required' Whether this element is required
 *     @item string  'label'? The display name for this element
 *     @item int:array '42'? Magic numbers array
 * }
 */


четверг, 16 октября 2014 г., 23:27:37 UTC+4 пользователь Mike van Riel написал:

Mike van Riel

unread,
Oct 18, 2014, 3:59:05 AM10/18/14
to php...@googlegroups.com
Thank you all for your input regarding this feature. In order to get a little overview I have compiled this summary of the discussion so far. Please note that this is mixed up with my opinion so this is not a completely objective summary but more a basis for refinement. I have tried to mention which items are my own opinion. Please correct me if I am wrong.

New proposal
-------------------

Before describing the results in the compiled summary I would like to do a new proposal based on this discussion. I am really interested to hear if you have objections to this notation.

```
@var array<string,mixed> $field {
    A field definition describing the information on how to render a single input element in a form.

    @element string 'label'
    @element string 'type'
    @element array  'options'? {
        @element boolean 'required'? Whether this field must have a value for the form to validate.
        @element string  'helpText'? A text that is shown with the field to provide additional information
    }
}
```

In the following chapters I summarize what has been discussed so far and what I see as caveats for certain options or just my opinion (since most of this is a matter of taste).

Topics
------

## Documenting key types

During the discussion the topic of documenting the type of a key has surfaced including suggestions for notations. As I see it no notation needs to be introduced for this as the variable name for the value already indicates what type it is and otherwise the Collection notation can be used: `array<keyType,valueType>`.

## Tag name for documenting an element

With regards to the tag name the opinion seems to be divided, a quick and partially inaccurate tally shows the following tag names that are suggested or used in examples (in order from most used to least used):

1. @type
2. @value
3. @key
4. @var
5. @item

I must admit that I am not fond of `@key` as I believe your are documenting an element, or record, of an array and not its key. For a similar, but less intense, reason I am unsure if `@value` fits the bill if you describe both key and value in the same tag (and splitting this up in two tags seems overly verbose to me).

I would also like to add another that I just thought of:

1. @element

Just as @property and @method are explicit for objects can @element be explicit for arrays. After comparing the semantics of each one my personal favorites are either `@item` or `@element` since one talks about array items or array elements. Though more characters in the end I prefer @element as I think it is the most name.

## Optional members

A variety of suggestions have come by but one thing appears to be dominant: you indicate which items are optional and each element is considered required by default.

The following notations have come by (all other parts are taken from the original proposal; this is only about the optional indication):

1. `@type integer $myInteger optional This is an optional number.`
2. `@type optional integer $myInteger This is an optional number.`
3. `@type integer $myInteger? This is an optional number.`
4. `@type:optional integer $myInteger This is an optional number.`
5. `@typeOptional integer $myInteger This is an optional number.`

My personal favorites are number 3 and 4; number 3 is nicely concise but number 4 is explicit and makes an interesting use of the new specialization notation.

## How to indicate variable name

One of the things that is under discussion is how to represent the key name for a given element in an array, here we also found several variations during the discussions:

1. `@type integer myInteger This is a number.`
2. `@type integer $myInteger This is a number.`
3. `@type integer 'myInteger' This is a number.`

I used to like option 2 but thanks to this topic I have shifted in favor of number 3. I hadn't considered number 3 before and there is one argument in specific that made me interested in this one: keys can have spaces (and other special characters). Option 1 and 2 will not work if a key has spaces in it.

## Nesting

The question arose whether it would be possible to have a nested array. The short answer is yes. All discussed notations support nesting. See the next chapter on notations for examples.

## Array vs. Objects

Another question was whether it would also be possible to document objects this way as sometimes you have anonymous objects (for example json-decoded output).
The proposal that I made supports this specific use-case:

```
@var object $myObject {
    This is a summary for this object.
   
    This is a description for this object.

    @property integer $myProperty
}
```

You can even use this to augment existing objects in case they do not have the right `@method` tags or otherwise expose magic behaviour that you'd want to capture:

```
@var MyMagicClass $object {
    @method string getMagic()
}
```

This last example also shows that the summary and description are entirely option (as with a normal DocBlock). This notation is also an example of 'Inline PHPDoc' where an entire PHPDoc can be nested inside another.

## Re-using definitions

The re-use of these definitions has also been requested but I am going to cover that in a different proposal (the `@typedef` tag). Even though I mention it here I would prefer if this is not discussed in this thread since this opens a whole new can of worms. This proposal is limited to defining an associative array inline with a DocBlock.

Notations
-------------

In addition to the notations above Bernhard suggested an alternative notation:

/**
 * @param array   $options           Additional options
 * @param boolean $options[required] Whether this element is required 
 * @param string  $options[label]    The display name for this element
 */

Although I agree that it has a natural feel to it I also comes with a few caveats:

- If a key contains a [ or ] character than this can be come awkward to read and parse
- This breaks current tooling because they expect only one @param per parameter
- this is not re-usable for object notations (at least not as far as I can imagine now)

And I personally think it is less skimmable than the original proposal because of a lack of indentation, though that is easily solved by adding your own:

/**
 * @param Service $myService
  * @param array   $options   Additional options
 *     @param boolean $options[required] Whether this element is required 
 *     @param string  $options[label]    The display name for this element
  */

compared to (notation of original proposal used for display purposes):

/**
 * @param Service $myService
  * @param array   $options {
 *     Additional options
 *     @type boolean $required Whether this element is required 
 *     @type string  $label   The display name for this element
 * }
  */

Larry Garfield

unread,
Oct 18, 2014, 12:00:11 PM10/18/14
to php...@googlegroups.com
Once again, Mike, thank you for the thorough writeup.


On 10/18/2014 02:58 AM, Mike van Riel wrote:
Thank you all for your input regarding this feature. In order to get a little overview I have compiled this summary of the discussion so far. Please note that this is mixed up with my opinion so this is not a completely objective summary but more a basis for refinement. I have tried to mention which items are my own opinion. Please correct me if I am wrong.

New proposal
-------------------

Before describing the results in the compiled summary I would like to do a new proposal based on this discussion. I am really interested to hear if you have objections to this notation.

```
@var array<string,mixed> $field {
    A field definition describing the information on how to render a single input element in a form.

    @element string 'label'
    @element string 'type'
    @element array  'options'? {
        @element boolean 'required'? Whether this field must have a value for the form to validate.
        @element string  'helpText'? A text that is shown with the field to provide additional information
    }
}
```

In the following chapters I summarize what has been discussed so far and what I see as caveats for certain options or just my opinion (since most of this is a matter of taste).

Topics
------

## Documenting key types

During the discussion the topic of documenting the type of a key has surfaced including suggestions for notations. As I see it no notation needs to be introduced for this as the variable name for the value already indicates what type it is and otherwise the Collection notation can be used: `array<keyType,valueType>`.

Since PHP only supports scalars as array keys (you need SplObjectHash if you want object keys on something, IIRC), and all scalars are always coercible to each other, when would you need to document the type of the key?  The value, sure, but the key?


## Tag name for documenting an element

*snip*


I would also like to add another that I just thought of:

1. @element

Just as @property and @method are explicit for objects can @element be explicit for arrays. After comparing the semantics of each one my personal favorites are either `@item` or `@element` since one talks about array items or array elements. Though more characters in the end I prefer @element as I think it is the most name.

I don't have a strong feeling here, but both @item and @element would be acceptable on my end. 

## Optional members

A variety of suggestions have come by but one thing appears to be dominant: you indicate which items are optional and each element is considered required by default.

The following notations have come by (all other parts are taken from the original proposal; this is only about the optional indication):

1. `@type integer $myInteger optional This is an optional number.`
2. `@type optional integer $myInteger This is an optional number.`
3. `@type integer $myInteger? This is an optional number.`
4. `@type:optional integer $myInteger This is an optional number.`
5. `@typeOptional integer $myInteger This is an optional number.`

My personal favorites are number 3 and 4; number 3 is nicely concise but number 4 is explicit and makes an interesting use of the new specialization notation.

There was one other option proposed I think is worth considering:

@item string 'foo'='bar' Some description here.

That is, if the key is omitted it will behave as if you passed "bar". If you do not omit it, it will do, er, whatever it is you passed.  That implies the value is optional since otherwise having a default would be nonsensical.  That is the same logic as PHP itself uses for parameter passing.  I think the idea has merit.

If not that, then I agree option 3 (@element string 'foo'?) is far and away the best of the other options.


## How to indicate variable name

One of the things that is under discussion is how to represent the key name for a given element in an array, here we also found several variations during the discussions:

1. `@type integer myInteger This is a number.`
2. `@type integer $myInteger This is a number.`
3. `@type integer 'myInteger' This is a number.`

I used to like option 2 but thanks to this topic I have shifted in favor of number 3. I hadn't considered number 3 before and there is one argument in specific that made me interested in this one: keys can have spaces (and other special characters). Option 1 and 2 will not work if a key has spaces in it.

Agreed on 'foo', for various reasons already stated.


## Array vs. Objects

Another question was whether it would also be possible to document objects this way as sometimes you have anonymous objects (for example json-decoded output).
The proposal that I made supports this specific use-case:

```
@var object $myObject {
    This is a summary for this object.
   
    This is a description for this object.

    @property integer $myProperty
}
```

You can even use this to augment existing objects in case they do not have the right `@method` tags or otherwise expose magic behaviour that you'd want to capture:

```
@var MyMagicClass $object {
    @method string getMagic()
}
```

This last example also shows that the summary and description are entirely option (as with a normal DocBlock). This notation is also an example of 'Inline PHPDoc' where an entire PHPDoc can be nested inside another.

Interesting... I'd not considered the potential for this syntax to extend to documenting common/expected dynamic values.  The intent here is then something like:

/**
 *
 * @var Foo $object {
 *   @method int bar() The number of bars.
 * }
 */
class Foo {
 
  /**
   *
   * @return int
   *   The amount of stuff.
   */
  public function stuff() {
    return $this->arr['stuff'];
  }

  public function __get($key) {
    return $this->arr[$key];
  }
}

Right?


--Larry Garfield

Mike van Riel

unread,
Oct 18, 2014, 12:47:47 PM10/18/14
to php...@googlegroups.com

On 18-10-14 17:59, Larry Garfield wrote:
Once again, Mike, thank you for the thorough writeup.

On 10/18/2014 02:58 AM, Mike van Riel wrote:
Thank you all for your input regarding this feature. In order to get a little overview I have compiled this summary of the discussion so far. Please note that this is mixed up with my opinion so this is not a completely objective summary but more a basis for refinement. I have tried to mention which items are my own opinion. Please correct me if I am wrong.

New proposal
-------------------

Before describing the results in the compiled summary I would like to do a new proposal based on this discussion. I am really interested to hear if you have objections to this notation.

```
@var array<string,mixed> $field {
    A field definition describing the information on how to render a single input element in a form.

    @element string 'label'
    @element string 'type'
    @element array  'options'? {
        @element boolean 'required'? Whether this field must have a value for the form to validate.
        @element string  'helpText'? A text that is shown with the field to provide additional information
    }
}
```

In the following chapters I summarize what has been discussed so far and what I see as caveats for certain options or just my opinion (since most of this is a matter of taste).

Topics
------

## Documenting key types

During the discussion the topic of documenting the type of a key has surfaced including suggestions for notations. As I see it no notation needs to be introduced for this as the variable name for the value already indicates what type it is and otherwise the Collection notation can be used: `array<keyType,valueType>`.

Since PHP only supports scalars as array keys (you need SplObjectHash if you want object keys on something, IIRC), and all scalars are always coercible to each other, when would you need to document the type of the key?  The value, sure, but the key?
This is an often request feature, though I agree that I think it is mostly for academic reasons, that is why the key part of the Collection notation is optional.
I expect to see `array<valueType>` or `Collection<valueType>` far more often. Nonetheless, it adds no significant effort and complexity to add support for defining the key's type as part of the Collection syntax and will make sure no missed use-cases are made prohibited. (people must request this or a reason)


## Tag name for documenting an element

*snip*

I would also like to add another that I just thought of:

1. @element

Just as @property and @method are explicit for objects can @element be explicit for arrays. After comparing the semantics of each one my personal favorites are either `@item` or `@element` since one talks about array items or array elements. Though more characters in the end I prefer @element as I think it is the most name.

I don't have a strong feeling here, but both @item and @element would be acceptable on my end. 

## Optional members

A variety of suggestions have come by but one thing appears to be dominant: you indicate which items are optional and each element is considered required by default.

The following notations have come by (all other parts are taken from the original proposal; this is only about the optional indication):

1. `@type integer $myInteger optional This is an optional number.`
2. `@type optional integer $myInteger This is an optional number.`
3. `@type integer $myInteger? This is an optional number.`
4. `@type:optional integer $myInteger This is an optional number.`
5. `@typeOptional integer $myInteger This is an optional number.`

My personal favorites are number 3 and 4; number 3 is nicely concise but number 4 is explicit and makes an interesting use of the new specialization notation.

There was one other option proposed I think is worth considering:

@item string 'foo'='bar' Some description here.

That is, if the key is omitted it will behave as if you passed "bar". If you do not omit it, it will do, er, whatever it is you passed.  That implies the value is optional since otherwise having a default would be nonsensical.  That is the same logic as PHP itself uses for parameter passing.  I think the idea has merit.
Interesting, you are right that my summary missed that one. You (and others) are also right that it might be worth documenting the default. Perhaps adding both is an option where ? acts as a shorthand for `=null` (effectively also saying `=undefined`).

If not that, then I agree option 3 (@element string 'foo'?) is far and away the best of the other options.
<snip>
Sorry, can you elaborate on your example? A class doesn't support the @var tag. Did you perhaps intend to use the @property tag to dynamically add a new property named $object to the class Foo, that is intended to contain an object of class Foo that in turn has a dynamically defined method bar()?

Drew Jaynes

unread,
Oct 18, 2014, 1:02:19 PM10/18/14
to php...@googlegroups.com
Thanks again Mike for following up here. Good stuff.

## Documenting key types

<snip>


1. @type
2. @value
3. @key
4. @var
5. @item


I agree on maybe using @element, especially as it's closer being explicit like @property and @method.


## Optional members


1. `@type integer $myInteger optional This is an optional number.`
2. `@type optional integer $myInteger This is an optional number.`
3. `@type integer $myInteger? This is an optional number.`
4. `@type:optional integer $myInteger This is an optional number.`
5. `@typeOptional integer $myInteger This is an optional number.`

My personal favorites are number 3 and 4; number 3 is nicely concise but number 4 is explicit and makes an interesting use of the new specialization notation.


Hmm. I'm not really a fan of either #3 or #4. I think semantically it's not clear what ? (#3) means at first grok. I think it's important to remember that inline docs need to be understandable in the code as well as in parsed documentation. Specializing the tag in #4 makes the intent vastly more obvious, but could really start making lines quite long, especially if you're aligning.

Case in point, we're 38 characters in before even get to the description. And that's for a short key name:
@element              boolean $myBool     This is my description.
@element:optional integer  $myInteger This is my description.

I guess my question would be  ... what's the current standard for marking regular @param values as optional? Can we mimic that?

## How to indicate variable name

1. `@type integer myInteger This is a number.`
2. `@type integer $myInteger This is a number.`
3. `@type integer 'myInteger' This is a number.`

I think I could get on board with 'myInteger'. I still think the $ would ease parsing but it's definitely a little less ambiguous with quotes..

# Notation

/**
 * @param Service $myService
 * @param array   $options   Additional options
 *     @param boolean $options[required] Whether this element is required
 *     @param string  $options[label]    The display name for this element
 */
 
compared to (notation of original proposal used for display purposes):
 
/**
 * @param Service $myService
 * @param array   $options {
 *     Additional options
 *     @type boolean $required Whether this element is required
 *     @type string  $label   The display name for this element
 * }
 */

I think I'm biased toward the original proposal, though I'd add a new line after the description. I think from a parsing perspective it'll be a lot more difficult to snag the description followed by the opening brace than it would be to simply have the hash description on a new line just inside the hash. And this applies in nesting situations as well.

In some ways, this again harkens back to the idea that DocBlocks should be readable in the source first, then in parsed docs.

Mike van Riel

unread,
Oct 18, 2014, 1:39:25 PM10/18/14
to php...@googlegroups.com

On 18-10-14 19:02, Drew Jaynes wrote:
<snip>


## Optional members

1. `@type integer $myInteger optional This is an optional number.`
2. `@type optional integer $myInteger This is an optional number.`
3. `@type integer $myInteger? This is an optional number.`
4. `@type:optional integer $myInteger This is an optional number.`
5. `@typeOptional integer $myInteger This is an optional number.`

My personal favorites are number 3 and 4; number 3 is nicely concise but number 4 is explicit and makes an interesting use of the new specialization notation.


Hmm. I'm not really a fan of either #3 or #4. I think semantically it's not clear what ? (#3) means at first grok. I think it's important to remember that inline docs need to be understandable in the code as well as in parsed documentation.
Even worse: my first priority lies in that it needs to be understandable in the code first! Tooling is nice and all but when push comes to shove you should be able to rely on a single information source, your repository. (that is why I belief in ReST or to a lesser extent Markdown documentation in your repo!)

Specializing the tag in #4 makes the intent vastly more obvious, but could really start making lines quite long, especially if you're aligning.

Case in point, we're 38 characters in before even get to the description. And that's for a short key name:
@element              boolean $myBool     This is my description.
@element:optional integer  $myInteger This is my description.
I agree, that length is an issue. That is actually why the ? was one of my favourites. That and the similarity to the ? regex operator.

Have you also seen Larry's post a few minutes ago where he addresses the default notation? (`@element integer $myInteger=0`)

I guess my question would be  ... what's the current standard for marking regular @param values as optional? Can we mimic that?
There is none. It is always assumed that whether a parameter is optional is deduced from the method signature. That is not possible in this case.


## How to indicate variable name

1. `@type integer myInteger This is a number.`
2. `@type integer $myInteger This is a number.`
3. `@type integer 'myInteger' This is a number.`

I think I could get on board with 'myInteger'. I still think the $ would ease parsing but it's definitely a little less ambiguous with quotes..
Parsing $ and '' is not that much different; you need to be a little craftier with the regex ;) I am actually working on a proof of concept Lexer to test out these changes and that I can use in phpDocumentor.


# Notation

/**
 * @param Service $myService
 * @param array   $options   Additional options
 *     @param boolean $options[required] Whether this element is required
 *     @param string  $options[label]    The display name for this element
 */
 
compared to (notation of original proposal used for display purposes):
 
/**
 * @param Service $myService
 * @param array   $options {
 *     Additional options
 *     @type boolean $required Whether this element is required
 *     @type string  $label   The display name for this element
 * }
 */

I think I'm biased toward the original proposal, though I'd add a new line after the description. I think from a parsing perspective it'll be a lot more difficult to snag the description followed by the opening brace than it would be to simply have the hash description on a new line just inside the hash. And this applies in nesting situations as well.
For a parser this does not matter much; I think it is good to allow both types and be whitespace-insensitive surrounding the brackets. Coding Standards can decide which way to actually go.

Larry Garfield

unread,
Oct 18, 2014, 3:14:00 PM10/18/14
to php...@googlegroups.com
*snip*



Right?
Sorry, can you elaborate on your example? A class doesn't support the @var tag. Did you perhaps intend to use the @property tag to dynamically add a new property named $object to the class Foo, that is intended to contain an object of class Foo that in turn has a dynamically defined method bar()?

I guess I misunderstood what you were talking about with "magic" then. Ignore my sample; can you provide an example of what you meant there?  Because  I apparently misunderstood it.

--Larry Garfield
Reply all
Reply to author
Forward
0 new messages