PHPDoc - Documenting #param's without the param in the function? - php

I'm currently building up some phpdoc for a restful API - and I took to using the #param doc syntax for notating required params over POST.
However, after generating the phpdoc, I noticed that it refuses to list these parameters unless they match exactly with input variables into the method itself.
#uses and #see don't look good nor make much sense here when it comes to the phpdoc output. The style/look of the doc is perfect with the #param functionality.
Is there any way to override the rules put in place by PHPDoc, and allow it to generate #param blocks in the documentation, even if the param doesn't exist in the method itself?

If you want to document your API, I suggest you use proper tools like API Blueprint or Open API Spec.
And by using Swagger, you can even use annotations (which is what you apparently want) to document the API and in turn, generate the documentation out of it.
Just don't use PHPdoc for it, because that's just mixing concepts altogether.

Alright, I'm going to answer this with the solution I've found - I appreciate all the "do not do that" answers, but still hope that someone who finds themselves in a similar situation to myself ala "this needs to be done immediately without changing the format, and we cannot allot any time to this" will find it useful in the future.
You can maintain using the #param syntax if you initialise the method with the param specified, and simply set it to null - ensuring it doesn't break any existing calls.
/**
* Remove a group
*
* #param int $pricing_group_id Required
* #return mixed JSON array with remaining groups
*/
public function remove($pricing_group = null) {
....
}
Your PHPDoc output will now show the param type, name, and description as normal.
Keep in mind that this is not good practice - nor is it even remotely correct practice. But it'll work until you can convince a higher-up to allot you enough time to rebuild the existing documentation on a more suitable platform.

You can do this by utilizing "optional". IE:
#param string $variable (optional) Blah.
See other examples at https://manual.phpdoc.org/HTMLSmartyConverter/HandS/phpDocumentor/tutorial_tags.param.pkg.html .
This is to be used in the use case of when a parameter is optional, unlimited parameters, etc.

You might consider using a "custom" tag, maybe #parameter, so that it is listed "as is". You won't get the same hyperlink behavior for class names as the param tag provides, but you won't be limited by the lack of parameters in the code signature itself. Maybe use an inline link tag in the parameter description that points to the class type of the parameter. Otherwise, the uses, see, or link regular tags can be on separate lines as convenient links to the classes that are your parameter types.
There is currently no way to disable the internal behavior of "actual code signature overrides param tags" logic.

I believe you can use the same approach for documenting virtual methods as a workaround, i.e. via a #method entry in the phpDoc header for the class.
E.g.:
/**
* ...
*
* #method mixed remove(integer $pricing_group_id) Remove a group and return a JSON array with remaining groups.
*/
class YourClass {
...
// see class header for phpdoc entry
public function remove($pricing_group = null) {
....
}
}
A downside is that (to my knowledge) this approach does not provide a means to enter explicit description entries for the method's parameters and return value.

Related

How can I document ZF1 helper to get an autocomplete in my IDE

I'm working with ZF1 and we have helpers in the project. By default IDE doesn't understand which class will be returned in that expression:
$this->getHelper('CRM')->getModeDependantLink($url);
So the system doesn't what will be returned by $this->getHelper('CRM') and can't find the method getModeDependantLink()
I can write this code in two lines to achieve the goal:
/** #var Lead_Helper_CRM $helperCRM */
$helperCRM = $this->getHelper('CRM');
$helperCRM->getModeDependantLink($url);
The PHPDoc explains to the IDE that $this->getHelper('CRM') returns object of Lead_Helper_CRM and then IDE knows everything about method getModeDependantLink()
But I don't like 2 lines of code. I'd like to get the same, but for one line code, something like:
/** #class Lead_Helper_CRM $this->getHelper('CRM') */
$this->getHelper('CRM')->getModeDependantLink($url);
Could please someone tell me if it possible to do with some PHPDoc trick? If yes, could you please show me a simple rough example how it can be done?
The only possibility might be the #return tag on the getHelper() method.
If it lists all possible returned classes,
and if your IDE knows how to interpret that
(and thus shows all potential methods from all those potential classes)...
That is the only scenario where what you want (method popup against the getHelper()->) might work.

PHPDoc for parameters and return type

I'm using eclipse to build my php applications and the Source > Generate Element Comment function for automatically creating doc blocks.
I'm wondering a bit about the format because the return type is set as full-qualified class name but the parameters not.
Is this a bug of the IDE or is it the common convention?
Here's an example:
/**
* Executes the given service.
*
* #param string $serviceClass
* #param ParametersInterface $inputParams
*
* #return \ZF\Hal\Entity
*/
And I have the following uses:
namespace MyApp;
use ZF\Hal\Entity;
use Zend\Stdlib\ParametersInterface;
It's most likely just a behavior oddity in Eclipse, where the auto-recognition code for parameters is possibly not the same code that auto-recognizes returns. I would bet the parameter recognition is more naive, in that it probably keys specifically off your method signature. So, if your method signature is
public function executeService(string $serviceClass, ParametersInterface $inputParams)
then the auto-doc probably gets exactly just the ParametersInterface you have in the code.
However, if you wrote the code this way
public function executeService(string $serviceClass, Zend\Stdlib\ParametersInterface $inputParams)
then I'd bet the auto-doc would show the fully namespaced name.
It wouldn't hurt to report it to Eclipse (if it's not already been reported).
This may happen if you have use ParametersInterface; with it's path on top of file, so PHP doc takes it into account, but you don't have use ZF\Hal\Entity, so it's inserted in #return with full path.
In PHPStorm it works like this, so probably in Eclipse it works the same

PHP Doc generic type declaration

I'm working on a library which uses the phpDocumentor specification on determining the type system using reflection. However, I couldn't find any information about generic type declarations.
Is there any way a generic type declaration should be specified?
For example: is there any specification (in-progress) which specifies anything like:
/**
* #template <T extends Base>
*/
class Collection {
/**
* #return Iterator<T>
*/
function get_iterator();
}
Note that the code above is just an example to illustrate what I mean by generic type declarations. I do not want this achieve anything to do with collections and iterators.
There apparently was some interest in the related topic of object specialization because that was added to PSR-5:
generic = collection-type "<" [type-expression "," *SP] type-expression ">"
Edit: and then removed as Jack notes below, albeit with a stated expectation that they'll return in one form or another before it's standardised
However, it doesn't provide a means to define a class as generic, and PSR-5 has been abandoned for a long while. The de-facto standard, phpDocumentor, does not in any way define support for such syntax.
If you want to informally mark up generics, you're best off making up your own syntax (inspired by similar syntax that already exists like Closure's documentation or JSDoc) while carefully avoiding anything that could actively confuse phpDocumentor, something like:
/**
* #template {Base} T
*/
/**
* #return Iterator {Iterator<T>}
*/
If you want to do it formally, you'll need to switch to another documentation system like doxygen.
You might want to check out the psalm project.
https://psalm.dev/docs/
https://github.com/vimeo/psalm
It supports generics in the documentation, as well as so much more. It's also used by Symfony's DB ORM, doctrine.
It supports Emacs, Phpstorm/Intellij, vim, and visual studio
Psalm supports this via
/**
* #template T of Foo
*/
Ref: https://medium.com/vimeo-engineering-blog/uncovering-php-bugs-with-template-a4ca46eb9aeb

specify #return type in phpdoc based on input parameter value

Does anyone know any way to specify #return type based on the input parameter?
My project has a lot of method calls such as
...->getComponent('name')->someMethod()
where getComponent is a service locator and IDE doesn't understand which value it returns.
For the PhpStorm IDE, you can create one or more files called .phpstorm.meta.php in your project. Here is an example content of such a file:
<?php
namespace PHPSTORM_META {
override(\Factory::getComponent(), map([
"name" => \some\namespace\Name::class,
"exception" => \Exception::class,
]));
}
You can find the documentation here:
https://www.jetbrains.com/help/phpstorm/ide-advanced-metadata.html#map
I recommend committing this file to make auto-completion available to other PhpStorm users.
The only way would be to have getComponent()'s #return tag actually list out all possible data types that could return. This kind of dynamic, loose typing behavior that PHP allows for is not conducive to such static resolution as done by an IDE autocomplete. It has always been a tough case to try to document, because your API doc is just as "static" as the "object tree" that an IDE has to construct in order to provide autocompletion.
If IDE autocompletion is urgent enough to warrant adjusting the code to make it happen, then aside from my earlier
#return ClassOne|ClassTwo|...|ClassInfinitum option,
you could split the two calls rather than chaining them, and use an #var "local docblock" that some IDEs know how to recognize:
// this litte docblock establishes the data type for the local variable $nameComponent
// note however that some IDEs want "datatype varname",
// some want "varname datatype",
// and some don't recognize the docblock at all
/** #var \NameClass $myComponent */
$nameComponent = $service->getComponent('name');
// here, the known methods of NameClass should pop up after typing ->
$nameComponent->

What is the proper way to document files, classes and constructors?

What is the most useful/most standard/least surprising way to consistently write comment blocks for constructors and classes and files containing just a single class?
Comment blocks for classes, not constructors
Comment blocks for constructors, not classes
Comment blocks for both constructors and classes -> In that case what sort of details should go in each?
And then the file itself? Does this need a comment block if it just contains a single class? What details should go there?
I want to try and avoid, as much as possible, repetition between class, constructor and file comment blocks.
This is highly depending on your context and the assumed skill level of the people you work with or the people that come after you.
If you publish a framework, a library or something of the sort you usually assume that your user are of all skill levels so you might want to document as much trivial crap as possible to reduce the load of questions your community has to handle.
Let me start of with an example where I think documentation can be a major pain.
What do you absolutely need
If you want to use PHPDoc you need a file doc block and another doc block after that (usually the class doc block).
Those **need* to have a #package Tag. Everything else is optional.
I'd go so far and say that even the #package Tag is optional since you might be able to automatically generate it for project. And if i remember correctly PHPDoc lets you even set a default package for everything that doesn't have a tag.
For documentation in general let me start of with an example (a longer example is at the end):
How many times can you explain what "uri" means:
Note that for getUri it is explained what URI stands for (just to have something to talk about in the comment I'd assume) while it isn't in isAbsUri because there you can at least say "abs means absolute" twice.
If you are not an open source project (or need to ship COMPLETE!!!11eleven api documentation):
I'd strongly suggest to use proper, long and descriptive class, variable and method names instead of documentation.
There is no gain in writing something again in the doc blocks and since it is 2011 and we have 120 char wide terminals and autocompletion there is just no need anymore to abbreviate everything for the sake of saving some chars.
I'd even argue that documenting trivial things hurts you and your team by forcing you to waste time on things nobody gets value from you get into a habit of always writing trivial docs and not reading them anymore.
A good comment should explain WHY something was done while the code its self should explain HOW without needing further comments.
My favorite example for redundant docs is this one:
class myClass {
/**
* Constructor
*/
public function __construct() {
}
Some guidelines say you HAVE to document EVERYTHING and you end up with people stating the obvious again and again.
This adds no value but wastes time when reading the code.
An example for proper naming:
class Person {
/**
* Set a persons weight in Kilogram
*
* #param float $kg Weight in Kilogram
*/
public function setWeight($kg) {}
This code is easy to document because you need to explain what "kg" means because some people might use a different system and you can't google for "kg".
I'm in favor of writing
class Person {
/**
* #param float $kilogram
*/
public function setWeight($kilogram) {}
The doc block is superfluous because calling setWeight on Person can REALLY be expected to set the Weight on a Person. No need to write that out again.
Using $kilogramm as a parameter also saves you the trouble of explaining it in the docs and I'd say, depending on your environment, everyone can be expected to google for "kilogram" if he really doesn't know the measurement unit.
#PHPDoc documentation
All my humble opinion of course
If you don't use type-hinting always use #param tags.
Always use #return tags
Don't use #author tags at all. Collection code ownership is more valuable and the information is in the source control repository anyways.
Only use #copyright tags if you have to. I like only having a LICENSE file but I'm not a lawyer so it might be necessary.
Inline comments:
public function generateReport() {
// get the db connection
$reg = WhateverGlobalStorage::get(“db“);
// auth
if(!$reg->getOne("SELECT view_report FROM USER ...")) {}
// template
$id = $reg->getOne("select ... ");
// render
new ReportTemplate($id); // ...
}
If those are separate "blocks" just move them to descriptive named functions
public function generateReport() {
$this->checkAuthentication();
$template = this->createReportTemplate();
$this->renderReport($template);
}
// Not perfect but at least you can grasp what the method does much quicker
Additional resources:
Slides of a presentation I gave on the subject on some conferences: Slideshare: clean-code-stop-wasting-my-time
And additional small, little older, rant: they-told-you-to-document-everything-they-lied
Book references:
Clean Code: A Handbook of Agile Software Craftsmanship
Refactoring: Improving the Design of Existing Code
A longer example
abstract class xyzRequest {
/**
* Initializes this xyzRequest.
*
* Available options:
*
* * logging: Whether to enable logging or not (false by default)
*
* #param xyzEventDispatcher $dispatcher An xyzEventDispatcher instance
* #param array $parameters An associative array of initialization parameters
* #param array $attributes An associative array of initialization attributes
* #param array $options An associative array of options
*
* #return bool true, if initialization completes successfully, otherwise false
*
* #throws <b>xyzInitializationException</b> If an error occurs while initializing this xyzRequest
*/
public function initialize(xyzEventDispatcher $dispatcher, $parameters = array(), $attributes = array(), $options = array()) {
Lets see, line by line, what that documentation tells you.
(I'm joking around here a little bit to get my point across)
* Initializes this xyzRequest.
So calling ->initialize on a xyzRequest initializes that request? Really? Ok then, if you say so!
* Available options:
*
* * logging: Whether to enable logging or not (false by default)
We are told the options for the third parameter, not for the second or third param but maybe we know those if we know the framework? (Since we are not able to figure out what ->initialize does without someone telling use we might not be that smart...)
* #param xyzEventDispatcher $dispatcher An xyzEventDispatcher instance
Yeah, the type-hint is there. So if the method expects a "xyzEventDispatcher instance" we need to pass in a "xyzEventDispatcher instance". Good to know.
* #param array $parameters An associative array of initialization parameters
* #param array $attributes An associative array of initialization attributes
* #param array $options An associative array of options
Ok. So it's not a linear array. But that I need to pass "initialization parameters" to an "initialize" method I could have figured out.
Still no clue what I actually need to pass in there but as long as its documented it has to be fine!
* #return bool true, if initialization completes successfully, otherwise false
So a boolean return value is "true" for "good" and "false" for bad".
* #throws <b>xyzInitializationException</b> If an error occurs while initializing this xyzRequest
*/
So an exception is thrown if an error occurs while we are doing what the function is named?
So exceptions are used for error cases. Ok. Good to know.
Doesn't tell me the difference between return false and an exception.
The #throws its self is fine because it adds information
Btw: Why is this BOLD and not a #link
Personally, I only comment in the constructors if there is something special to comment about it (like a special initialization).
I wouldn't say that's the "most useful" way to go, but it keeps the code neat, and repeating two times the same thing isn't really needed (if that's your concern).
Comment everything - files (authorship, copyright, description etc), classes (description, code examples), methods and properties. Here is a good example with phpDoc comments.
Personally I think that class and method documentation is the most important documentation around. When I write code I want the help of my IDE when the code completion shows me the documentation belonging to a method. This way I can easily find the method I need.
Since I try to keep the explicit initialization of classes to a minimum, I don't user constructor comments. Hence, I try to avoid the use of constructors itself.
The code in a method or function should be as clear as possible by using declarative variable names and keeping them so small as possible. Only when I do something unexpected, by example for integration issues I comment them.

Categories