Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Feature request: @method support for referencing magic methods #1085

Open
aimfeld opened this Issue · 6 comments

4 participants

Adrian Imfeld Vasil Rangelov Mike van Riel Kevin Herrera
Adrian Imfeld

After doing some research and asking on stackoverflow for a way to reference magic methods, and this seems currently not possible.

PHP frameworks use a lot of magic methods which poses a problem for IDEs since they have no easy way of linking method calls to the magic method implementation.

In ZF2 for example, controller plugins and view helpers are implemented with __invoke. These magic methods are documented with the @method tag (e.g. view helpers). However, IDEs like PHPStorm can only link the method calls to the @method tag, but not to the magic method __invoke directly.

Instead of documenting a viewhelper like BasePath like this

@method \Zend\View\Helper\BasePath basePath($file = null)

I think it would be helpful to be able to document it like this

@method basePath \Zend\View\Helper\BasePath::__invoke

Return types and parameters of the basePath() function could be determined from the __invoke method's phpdoc directly without repeating them in the @method tag. Also, it would be easier for IDEs to directly link to the magic method. Maybe it would be better to introduce a new tag instead of supporting an alternative usage for the @method tag?

Any thoughts on this idea?

Adrian Imfeld

I see that there is a proposal for an @alias tag, but it's not quite what I'm suggesting here, since @alias would be constrained to the same namespace.

Vasil Rangelov
Collaborator

I think what you're really talking about is documenting a RETURNED callback type and/or other non-objects in general.

And we've had that discussion at #830. As you can see, it's somewhat of a tricky issue to nail an appropriate syntax and semantics for.

Mike van Riel
Owner

Hello @aimfeld, can you please post a small sample of example code how you see this? I am having trouble getting a clear picture of what you are proposing. My main question is where and how would you want to refer to a 'magic method'?

In any context can you use the see or uses tag to relate directly to a magic method:

/**
 * @see \Zend\View\Helper\BasePath::__invoke
 */
function refersToBasePathHelper()
{
}
Kevin Herrera

I remember having a discussion just like this one some time ago.

I suggested using regular method docblocks, but including a @magic or @method tag to indicate that the docblock is for a magic method. The value for the tag would be the name of the magic method.

/**
 * This is an example class.
 */
class Example
{
    /**
     * This is the short description.
     * 
     * This is the long description.
     * 
     * @method methodName
     * @param integer $num A number.
     * @return integer Another number.
     */
}
Adrian Imfeld

@mvriel The basic idea is that the @method tag should support an optional link to magic method implementations. @see does not cover this in my opinion.

Ok, I'll try to clarify with some sample code for using ZF2's BasePath view helper.

namespace Zend\View\Helper;

class BasePath extends AbstractHelper
{
    /**
     * Returns site's base path, or file with base path prepended.
     *
     * $file is appended to the base path for simplicity.
     *
     * @param  string|null $file
     * @throws Exception\RuntimeException
     * @return string
     */
    public function __invoke($file = null)
    {
        //...
        return $this->basePath . $file;
    }
}

The __invoke function is called directly when $phpRenderer->basePath() is called, since the PhpRenderer class contains a magic __call function to relay to view helpers.

I can call this view helper from a viewscript:

<?php 
/** @var Zend\View\Renderer\PhpRenderer $this */

echo $this->basePath('/js/my.js');

ZF2 documents the basePath function as follows to support IDEs in giving better code assist:

namespace Zend\View\Renderer;

/**
 * @method \Zend\View\Helper\BasePath basePath($file = null)
 */
class PhpRenderer
{
}

I now get code assist for the basePath method when I type $this-> in my viewscript. However, the IDE cannot hyperlink $this->basePath() to the method implementation at \Zend\View\Helper\BasePath::__invoke(). So I need a lot of framework knowledge or a debugger to figure out where the call actually goes.

If it was possible to specify a link to the implementation in the method tag like this

/**
 * @method basePath \Zend\View\Helper\BasePath::__invoke
 */
class PhpRenderer
{
}

it would be easy for IDE's to actually link to the __invoke method. The return type and parameter list could be gleaned from the __invoke method instead repeating them in the @method tag. Redundant informaton gets out of sync quickly anyway.

As an alternative, the link to the __invoke method could just be optionally added at the end to maintain the current syntax and full controll over the return type and parameter list:

/**
 * @method string|\Zend\View\Helper\BasePath basePath($file = null) \Zend\View\Helper\BasePath::__invoke
 */
class PhpRenderer
{
}

I'm sure you can come up with a better syntax, but I hope I could clarify the idea.

Mike van Riel
Owner

If I understand this correctly your issue is that the __call() method uses a class as a functor and you cannot easily find out which class that is in the @method call.

I do not think this information belongs in the @method tag; quite simply put: it is an implementation detail of the __call() method and not of the class itself. This is architecturally an interesting solution, one I consider an edge case, and if I were to add @method tags on the class I would add @uses tags on the __call() method that refer to the individual helpers.

A different solution that is possible in the near future is to have an Inline PHPDoc with your @method tag that has an @see referring to the location where it is instantiated, for example:

/**
 * @method \Zend\View\Helper\BasePath basePath($file = null) {
 *     @see \Zend\View\Helper\BasePath::_invoke
 * }
 */

This is a new syntax that is still under discussion but we hope to conclude that in the near future

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.