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.
Related
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 having a bit of a problem trying to get a correct autocompletion for the following code example. I'm using PHPStorm 7 on a Win7 machine.
First just a simple class.
/**
* Class myObject
*/
class myObject
{
/**
* some method
*/
public function myMethod()
{
// do something
}
}
This one is the collection class which can contain multiple instances of the prior class and implements the IteratorAggregate interface.
/**
* Class myCollection
*/
class myCollection implements IteratorAggregate
{
/**
* #var myObject[]
*/
protected $_objects = array();
/**
* #param myObject $object
* #return myCollection
*/
public function add(myObject $object)
{
$this->_objects[] = $object;
return $this;
}
/**
* #return ArrayIterator
*/
public function getIterator()
{
return new ArrayIterator($this->_objects);
}
}
And here is the code example.
$collection = new myCollection;
$collection->add(new myObject);
$collection->add(new myObject);
foreach ($collection as $object) {
$object->myMethod(); // gets no autocompletion
}
As you may have guessed (and read in the example) the myMethod() call gets not autocompleted and is beeing listed in the code analysis. The only way i found is adding a comment block for $object, which i find, to be honest, extremely annoying.
/** #var $object myObject */
foreach ($collection as $object) {
$object->myMethod(); // gets autocompletion now, but sucks
}
So, any ideas or fundamented knowledge on how to solve this?
/**
* #return ArrayIterator|myObject[]
*/
public function getIterator()
{
return new ArrayIterator($this->_objects);
}
For extended classes (the base class is above):
/**
* #method myObject[] getIterator()
*/
class ExtendedClass extends BaseCollection
{
}
or
/**
* #method iterable<myObject> getIterator()
*/
class ExtendedClass extends BaseCollection
{
}
I think this will be best way to handle such case. at least it works with PHPStorm
Your
/** #var $object myObject */
block is indeed the correct way to accomplish this. The syntax you are expecting to do the work,
/**
* #var myObject[]
*/
is not standard phpdoc notation, although it is in informal use and has some effort ongoing to standardize. Until such standardization does happen, IDEs recognizing it will probably be hit-or-miss. IDE coverage of your $object local var block is also hit-or-miss, actually.
In your myCollection class, override current() as follows:
/** #return myObject */
public function current() {
return parent::current();
}
Possible workaround (also ugly) is to create static "constructor", that will return myObject. At least it works in eclipse. If you want to see collection methods too, then just add myCollection to return as "#return myObject[]|myCollection"
class myCollection implements \IteratorAggregate
{
/**
* #return myObject[]
*/
public function create()
{
return new static();
}
}
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.
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.