Follow-up to #1689 "Introduce procedural @implements tag..".
Currently both PHP and phpDocumentor allow "callable" as a type hint / type specifier. In phpDocumentor this can be used for @param, @return and @var/@type. However, there is no way to specify which signature is expected from the callable variable/argument.
Posts within #1689 have suggested more than one way to specify the expected signature:
Refine a
@param callable $f,@type callableor@var callablewith..
- ..an explicit signature specification, native PHP 7 style.
- ..an explicit signature specification, phpDocumentor style.
- ..a reference to a prototype function, to specify the callable signature.
- ..a reference to a prototype function, to specify the callable signature AND semantics.
In this issue I want to focus on the first two options, which do not require a prototype function or method to exist anywhere (hence the bold font).
Proposed by @mvriel, https://github.com/phpDocumentor/phpDocumentor2/issues/1689#issuecomment-167392060
/** * @param callable $f { * @signature (int $a, int $b) * } */
Proposed by @Fleshgrinder, https://github.com/phpDocumentor/phpDocumentor2/issues/1689#issuecomment-167402347
/** * @param {callable(int $a, int $b): string} $cb */
Proposed by @donquixote, https://github.com/phpDocumentor/phpDocumentor2/issues/1689#issuecomment-167440760
/** * @param callable $f { * @param int $a * @param string $b * @return X * @throws FooException * } * @return X|null */ function foo(callable $f) { try { return $f(5, 'x'); } catch (FooException $e) { return null; } }This would give us the full expressiveness of phpDocumentor, and allow even explanation text.
I don't know where in this example we would put a textual description of the $f argument.. within the brackets?
Btw, either syntax would allow us to omit the parameter names, if we want to.
(I personally prefer them with the name, because the name tells something about the semantics)
/**
* @param callable $knitmachine {
* @param int
* The number of colors to use for the socks.
* @return PairOfSocks
* A colorful pair of socks.
* }
* @param {callable(int, int): string}
*/
It is also quite educating to see what other languages are doing
C/C++, https://en.wikipedia.org/wiki/Function_pointer
char * (*func2)(const char *, int)
Here the name of the variable or parameter ("func2") is in the middle of the type specifier. Which, imo, is plain ugly.
C/C++ typedef:
typedef int(*PFN)(int);
Here the newly defined type name ("PFN") is in the middle of the type specifier, which again is ugly.
jsdoc:
http://usejsdoc.org/tags-callback.html
https://github.com/jsdoc3/jsdoc/issues/260
http://stackoverflow.com/questions/13403887/how-to-document-callbacks-using-jsdoc
Java lambdas:
http://www.javaworld.com/article/2092260/java-se/java-programming-with-lambda-expressions.html
Personally I have not found anything really convincing from these 3rd parties. I think we are better off to invent our own syntax, based on what is already existing in PHP and phpDocumentor.
What about something like:
<?php
/**
* @param (string, int) -> bool $arg
*/
Or (a more PHP 7 way):
<?php
/**
* @param (string, int): bool $arg
*/
What is the status of this one?
@jaapio what do you think about this?
With psr-5 still on hold due a leak off time we didn't make a decision yet how to implement this. All focus is currently on the new development of php 7+ support. Which is our most important goal for the upcomming v3 release. After we have released our first alpha release we will try to add new features.
But my first idea about this is that it could look the same way as magic methods are defined with the @method notation. We will have to see if and how we can support this. The @method tag is also missing support for return types for example.
Why not something like jsdoc's callback tag? http://usejsdoc.org/tags-callback.html
Has this been added yet?
Anything on this yet?
There was an RFC in PHP earlier in 2015 to address this in PHP itself, but it was rejected unfortunately: https://wiki.php.net/rfc/callable-types
And some discussion about their problems implementing, which probably won't apply here: https://github.com/php/php-src/pull/1667
Another RFC with a different syntax was proposed in 2016, but it doesn't look like any patch was provided, so it was never voted on: https://wiki.php.net/rfc/typesafe-callable
The WordPress open source project uses an adjusted version of the hash syntax for its array-type parameters:
@param array $foo {
@type string $bar This is a string
@type int $baz This is an integer
}
This syntax is clear, works well, and the use of @type for properties means existing parsers don't pick up extra @params. IDEs such as PHPStorm support it.
Might this be a good syntax to consider for callables?
Related WordPress issue for considering reusing this same syntax for documenting the expected parameters for callables: https://core.trac.wordpress.org/ticket/42509
Psalm and PHPStan have both adopted the short inline syntax:
@param callable(Type1, OptionalType2=, SpreadType3...):ReturnType $foo Bar
Frustratingly, this doesn't allow for descriptive information about the parameters passed to the callback to be provided.
Most helpful comment
What about something like:
Or (a more PHP 7 way):