Search code examples
phpidephpstorm

Typehinting through Zend_Registry::get() - how to make navigation to declaration understandable to PhpStorm?


You can pass anything to Zend_Registry::set('myWidget', $someWidget), so that it's available later on.

However, when you retrieve it elsewhere, PhpStorm IDE has no clues to the type of 'myWidget'.

<?php
class AwesomeWidget {
   public function doBazFlurgle() {
      // doesn't matter what exactly happens here
      return mt_rand();
   }
}
?>

<?php 
class FooController {

    public function init() {
        $someWidget = new AwesomeWidget();
        Zend_Registry::set('awesome', $someWidget);
    }

    public function barAction() {
        $this->init();
        $awesome = Zend_Registry::get('awesome');
        $awesomeNumber = $awesome->doBazFlurgle();
    }

}

Navigate to declaration on the ->doBazFlurgle() call gets me a "Cannot find declaration to go to".

  • I could add a /** @var AwesomeWidget $awesome */ annotation, but that would require editing in many places in a sizable codebase
  • I could also add a return type annotation to Zend_Registry, but that does not look very maintainable (there are many instances of different classes stored this way).
  • I could search for the string doBazFlurgle through Find In Path..., but that is not entirely convenient (many keystrokes as opposed to a single Ctrl+click)

I noticed that NetBeans is capable of jumping to the method definition in this exact situation; is there a simple way of doing the same in PHPStorm without going through "search the entire codebase for doBazFlurgle"? I have searched available IDE actions, plugins, and fora; all in vain.


Solution

  • There is a way: as pointed out by @LazyOne, making a list of "what is returned from where" helps the IDE make sense of such code; this is somewhat documented on Jetbrains' website:

    <?php
    /** @link https://confluence.jetbrains.com/display/PhpStorm/PhpStorm+Advanced+Metadata */
    // note that this is not valid PHP code, just a stub for the IDE
    namespace PHPSTORM_META {
        $STATIC_METHOD_TYPES = [
            \Zend_Registry::get('') => [
                'awesome' instanceof \AwesomeWidget, // this is the class as seen in the question
                'fooSetting' instanceof \Zend_Config, // this came in from application settings
                'quuxData' instanceof \ArrayAccess, // an arraylike object
            ]
        ];
    }
    

    Including this file (named .phpstorm.meta.php by convention) in the project has resolved the issue. This file is not valid PHP - PhpStorm only uses it for typehinting. That way, Zend_Registry::get('awesome')->doBazFlurgle() is correctly resolved as calling the method on an instance of \AwesomeWidget.