Take in consideration the following PHP 5 class:
class SomeClass
{
//I want to document this property...
private $foo;
function __construct()
{
}
public function SetFoo($value)
{
$this->foo = $value;
}
public function GetFoo()
{
return $this->foo;
}
}
How in phpDocumentor will I document the $foo property? I'm not even sure it need to be documented but I would like to know how if if needs to...
I know how to document SetFoo() and GetFoo(), I'm just not sure about the private property (variable?).
Thanks!
/**
* This is what the variable does. The var line contains the type stored in this variable.
* #var string
*/
private $foo;
I would generally use at least the #var tag, to indicate the type of variable this is.
For instance :
/**
* Some blah blah about what this is useful for
* #var MyClass $foo
*/
This is exactly what's done by Zend Framework, for instance ; see Zend_Layout (quoting) :
class Zend_Layout
{
/**
* Placeholder container for layout variables
* #var Zend_View_Helper_Placeholder_Container
*/
protected $_container;
/**
* Key used to store content from 'default' named response segment
* #var string
*/
protected $_contentKey = 'content';
Note : the #access tag was useful with PHP 4 (when there were no public/protected/private), but I never use it when I document code written in PHP 5 : the code, using the visibility keywords is self-documenting.
In the case you use a __get and __set magic methods you can use #property
/**
* Description for the class
* #property type $foo Description for foo
* #property type $foo Description for bar
*/
class SomeClass
{
private $foo;
protected $bar;
public function __get(){
...
}
public function __set(){
...
}
}
Links with more info:
http://www.phpdoc.org/docs/latest/for-users/phpdoc/tags/property.html
http://manual.phpdoc.org/HTMLSmartyConverter/HandS/phpDocumentor/tutorial_tags.property.pkg.html
/**
* docstring
*/
private $foo;
Important note: there should be two asterisks. Not one.
Related
Is there an opportunity, that will allow it to declare a variable in php as a specific object, so that IDEs like Netbeans can detect that Object and suggest me the possible methods and variable in that class?
What I know, is that it works with function like this example:
public static function add(\Event $element) {
//The $element variable is now declared, that it have to be an Event object
}
In the theory, my question looks like this:
\Event $events = EventContainer::getAll();
But unfortunately that wouldn't work.
In eclipse I usually use this pattern:
class Foo {
/**
* #var $barArray \Baz\Bar[]
*/
protected $barArray;
/**
* #var $bar \Baz\Bar
*/
protected $bar
/**
* #return \Baz\Bar
*/
public function getBar()
{
return $this->bar;
}
/**
* #return \Baz\Bar[]
*/
public function getAllBar()
{
return $this->barArray;
}
}
That way eclipse knows by the javadoc what to use in autocomplete. It might work the same in other editors.
Is there any way to mark a magic property as deprecated? Consider following, simplified code:
/**
* Example class
*
* #property string $foo A foo variable.
*/
class Example {
/**
* Magic getter
*/
public function __get($var) {
if('foo' === $var) {
// do & return something
}
}
}
Now, how to indicate other developers, that they should not use Example::$foo anymore? The only working solution that comes to my mind is:
/**
* Example class
*/
class Example {
/**
* A foo variable.
*
* #var string
* #deprecated
*/
public $foo;
/**
* Magic getter
*/
public function __get($var) {
if('foo' === $var) {
// do & return something
}
}
}
But this both breaks my code (getter is not called) and doesn't feel very elegant.
The #mixin approach works at least with PhpStorm:
/**
* class or trait for the {#mixin} annotation
*/
trait DeprecatedExampleTrait {
/**
* Declare it as private to increase the warning level
* #deprecated
* #var string
*/
public $foo;
}
/**
* Example class
*
* #mixin DeprecatedExampleTrait
*
* #property string $newFoo A foo variable.
*/
class Example {
/**
* Magic getter
*/
public function __get($var) {
if (in_array($var, ['foo', 'newFoo'])) {
// do & return something
}
}
}
$example = new Example;
$example->foo;
Screenshot:
This is not possible with PHPDoc as the #deprecated can only be associated with structural elements (documentation).
If it is really important for developers to know that they should no longer use this magic property, you could trigger an E_USER_DEPRECATED error:
/**
* Example class
*
* #property string $foo A foo variable.
*/
class Example {
public function __get($name)
{
if ($name === 'foo') {
trigger_error('Property $foo is deprecated and should no longer be used', E_USER_DEPRECATED);
}
// ...
}
}
To prevent users from using your deprecated property, you can just remove the PHPDoc for this property from your class header.
/**
* Example class
*
*/
class Example {
/**
* Magic getter
*/
public function __get($var) {
if('foo' === $var) {
// do & return something
}
}
}
This way, you'll keep your legacy code working, while the property will no longer be shown by IDE autocompletion tools etc.
i'm working with huge models on PHPStorm. I'm trying to minimize my annotations.
I want to turn this
Class Stack
{
/** #var string */
public $foo;
/** #var string */
public $bar;
/** #var int */
public $foobar;
}
into this:
Class Stack
{
/** #var string */ //for both vars
public $foo;
public $bar;
/** #var int */
public $foobar;
}
I found the ##+ syntax to define multiple vars but seems that is not working. Maybe there is a workaround?
Thank you very much.
By the way, can i tell phpstorm that
$this->MyModel is a MyModel type? Something like:
/** #var $this->MyModel MyModel **/
$this->MyModel
Because CodeIgniter puts all of your models inside a param of the controller.
I'm afraid that I've not seen any IDE that knows how to recognize the docblock template syntax of /*##+/.
As for $this->MyModel, you could try using the #property tag on that class where you are using $this->MyModel.
Although some IDEs can reportedly recognize that #var syntax to set a datatype on a local variable:
/** #var \MyModel $model */
$model = $this->MyModel;
I don't think it would work with a class property like that.
Why you cannot declare it with #property in the PHPDoc block of the class?
/**
* #property myModel MyModelClass
*/
class Test
{}
$t = new Test();
$t->myModel->[CTRL+Space will return available methods];
Anyway most better to declare property manually in the class. Just make it transparent.
It's really weird to use group comment for objects. I haven't had such practice.
But feel free to use similar code:
/**##+
* Test
*
* #var int
*/
protected $_aa = 1;
protected $_aa2 = 2;
/**##-*/
I have a method that accepts a callback as a parameter. I would like to provide a signature in the PHPDoc for the class method that outlines the parameters for the callback function to be passed to that method so that my IDE (PHPStorm) can produce valid type hints for functions that are passed to my method, or at least someone looking at the code can determine the signature of the callback they're intended to provide.
For example:
class Foo {
public $items = [];
/**
* #param Callable(
* #param ArrayObject $items The list of items that bar() will return
* ) $baz A callback to receive the items
**/
public function bar(Callable $baz) {
$items = new ArrayObject($this->items);
$baz($items);
}
}
The method bar has one parameter, $baz, which is a callback function. Any function passed as an parameter to bar() must accept an ArrayObject as its only parameter.
Ideally, it should be possible to include multiple parameters for the Callable, just like for any other method.
When I write the following code:
$foo = new Foo();
$foo->bar(function(
...I should then receive a parameter list that correctly hints the type (ArrayObject) of the accepted parameter for this function call.
Is such a thing possible? Does PHPStorm or another IDE support it? Is there a recommended/standard way of documenting this even if there is no IDE support?
PHP 7+:
Using an interface for the callable combined with anonymous classes will do the trick. It's not very handy and leads to bit too complex code for the class-consumer, but currently it's the best solution in terms of static code-analysis.
/**
* Interface MyCallableInterface
*/
interface MyCallableInterface{
/**
* #param Bar $bar
*
* #return Bar
*/
public function __invoke(Bar $bar): Bar;
}
/**
* Class Bar
*/
class Bar{
/**
* #var mixed
*/
public $data = null;
}
/**
* Class Foo
*/
class Foo{
/**
* #var Bar
*/
private $bar = null;
/**
* #param MyCallableInterface $fn
*
* #return Foo
*/
public function fooBar(MyCallableInterface $fn): Foo{
$this->bar = $fn(new Bar);
return $this;
}
}
/**
* Usage
*/
(new Foo)->fooBar(new class implements MyCallableInterface{
public function __invoke(Bar $bar): Bar{
$bar->data = [1, 2, 3];
return $bar;
}
});
If you're using PhpStorm it will even auto-generate the __invoke-Method's signature & body within the anonymous class.
I overcame this problem by defining a static function within the class using the callable. That function has its own doc-block and I just refer to it in the method that's requiring my callable using PHPDoc's #see tag.
class Foo
{
/**
* Description of the "bar" callable. Used by {#see baz()}.
*
* #param int $index A 1-based integer.
* #param string $name A non-empty string.
* #return bool
* #see baz()
* #throws \Exception This is a prototype; not meant to be called directly.
*/
public static barCallable($index, $name)
{
throw new \Exception("barCallable prototype called");
}
/**
* Description of the baz() method, using a {#see barCallable()}.
*
* #param callable $bar A non-null {#see barCallable()}.
* #see barCallable()
*/
public function baz(callable $bar)
{
// ...
call_user_func($bar, 1, true);
// ...
}
}
This works well in PhpStorm 10. the Quick Documentation allows to navigate from the method documentation to the prototype documentation easily.
I make my prototype function throw an exception to make it clear it's not meant to be called. I could use a protected or private scope, but then PHPDoc would not always pick the doc-block for documentation generation.
Unfortunately PhpStorm can't track usage of callbacks. It doesn't provide Parameter Info either when using the method requiring a callback, but the callback is at least formally documented.
This approach also has the added benefit of validating a callback definition from the reflection of the prototype at run-time.
It is not possible in PhpStorm by now. I can't even think of other solution which do relatively the same by other means.
How do I mark a method as "returns an instance of the current class" in my phpDoc?
In the following example my IDE (Netbeans) will see that setSomething always returns a foo object.
But that's not true if I extent the object - it'll return $this, which in the second example is a bar object not a foo object.
class foo {
protected $_value = null;
/**
* Set something
*
* #param string $value the value
* #return foo
*/
public function setSomething($value) {
$this->_value = $value;
return $this;
}
}
$foo = new foo();
$out = $foo->setSomething();
So fine - setSomething returns a foo - but in the following example, it returns a bar..:
class bar extends foo {
public function someOtherMethod(){}
}
$bar = new bar();
$out = $bar->setSomething();
$out->someOtherMethod(); // <-- Here, Netbeans will think $out
// is a foo, so doesn't see this other
// method in $out's code-completion
... it'd be great to solve this as for me, code completion is a massive speed-boost.
Anyone got a clever trick, or even better, a proper way to document this with phpDoc?
Update:
As of Netbeans 7.4, the IDE supports #return self, static, and this (http://wiki.netbeans.org/NewAndNoteworthyNB74#Editor_2).
class foo {
protected $_value = null;
/**
* Set something
*
* #param string $value the value
* #return this
*/
public function setSomething($value) {
$this->_value = $value;
return $this;
}
}
class bar extends foo {
public function someOtherMethod(){}
}
Previous Answer:
We have a similar issue with a record iterator's current() method. Since the iterator is extended for many different classes, it doesn't make sense to have a #return $class associated with it. We've used #satrun77's Option 2 before, but I've used #method with some success in Netbeans.
class foo {
protected $_value = null;
/**
* Set something
*
* #param string $value the value
* #return foo
*/
public function setSomething($value) {
$this->_value = $value;
return $this;
}
}
/**
* #method bar setSomething($value)
*/
class bar extends foo {
public function someOtherMethod(){}
}
Thought I'd revisit this Q as I came across a couple of things.
Currently "return $this" isn't supported, but there is a PhpDoc request to add exactly that in v1.5:
http://pear.php.net/bugs/bug.php?id=16223
There's also a request for it in Eclipse PDT:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=276082
Both are relatively old requests. I'm not going to get too excited about this being implemented any time soon, but here goes to hoping :) In the meantime, it seems there is no proper solution to this problem.
!SOLVED! - upgrade to netbeans 9.0 (stable as of July 2018?)
I have been after this for over a year and finally have an open source solution! :)
class Input extends BasicHtml
{
public function someOnlyInputFunc()
{
}
}
class Table extends BasicHtml
{
public function tableOnlyFunc()
{
}
}
abstract class BasicHtml
{
/**
*
* #param array $arrayForNow
* #return $this
*/
public function setStyle( array $arrayForNow )
{
return $this;
}
}
/////driver
$table = new Table();
$input = new Input();
$input->setStyle(array())->//now shows only Input + baseHtml functions
$table->setStyle(array())-> //now shows only Table + baseHtml functions
///note - in 8.0.2 version it shows blank obj drop downs on exact same code.
This also works with traits. As of 11/1/2018 9.0 comes as a big zip (no clean installer for windows, mac?) and you will have to search for adding the php plugings etc BUT IT DOES WORK! Took me about an hour to get it all set. I also have my old 8.x installed and running along side the new 9.0 without issue...so far (just don't run them both at same time). Plugin tip: https://www.reddit.com/r/PHP/comments/9gtaaw/how_to_run_netbeans_9_with_php_support/
Here is 3 work around:
(These are just work around. classes must not be designed and implemented to sue the behavior of an IDE)
Option 1:
make the method someOtherMethod abstract or empty method in foo class
class foo implements ifoo {
protected $_value = null;
/**
* Set something
*
* #param string $value the value
* #return ifoo
*/
public function setSomething($value) {
$this->_value = $value;
return $this;
}
// abstract method or create empty method if you want the method to be
// to be optional
abstract function someOtherMethod();
}
Option 2:
Override the method setSomething in bar class
class bar extends foo {
/**
*
* #param <type> $value
* #return bar
*/
public function setSomething($value) {
return parent::setSomething($value);
}
public function someOtherMethod(){}
}
Option 3:
Use interface
interface ifoo {
public function someOtherMethod(){}
}
class foo {
protected $_value = null;
/**
* Set something
*
* #param string $value the value
* #return ifoo
*/
public function setSomething($value) {
$this->_value = $value;
return $this;
}
}
class bar extends foo implements ifoo {
public function someOtherMethod(){}
}
phpDoc syntax allows for multiple types to be defined by separating them with a | character for the #return tag. When you extend the class foo with class bar you should write a new phpDoc tag that has the proper class for its #return.
If a function returns either foo or bar then you would use #return foo|bar.
However in your case just define #return bar for the overridden function.
Take care.