5

I'm using Pimple dependency injector, and every time I use a dependency from the container, I can't help but to double check the spelling of the key used to get the dependency:

$ioc = new Pimple();

// 1. Define some object
$ioc["some-key"] = $ioc->share(function($c){ /* ... */});

// 2. Use it
$ioc["som... // Open config file and check spelling...

Does PHPStorm have some way of looking up those properties and providing auto-completion? I have considered defining all those keys using something like

define('SOME_KEY', 'some-key');

// ...

$ioc[SOME_KEY] = $ioc->share(/* ... */);

but I wonder if there's a better way.

Edit

Here's some sample code:

// project_root/library/App/Injector/Ioc.php
require_once "Pimple.php";

/** @var array|Pimple $ioc */
$ioc = new Pimple();

$ioc["version"] = "1.0.1650.63";

$ioc["location-service"] = $ioc->share(function ($c) {
     return new Application_Service_Location();
   }
);

It turns out that string auto-completion works fine whether or not I include /** @var array|Pimple $ioc */ before the $ioc declaration in the same file as $ioc is declared. However, since I'm using Zend Framework, I'm usually using $ioc thusly:

// project_root/Application/Bootstrap.php
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap {
   protected function _initInjector() {
     $ioc = null;
     require_once LIBRARY_PATH . "/MFM/Injector/ioc.php";
     Zend_Registry::set("ioc", $ioc);
   }
}

// project_root/Application/Controllers/SomeController.php
class Application_Controller_SomeController extends Zend_Controller_Action {
   public function IndexAction() {
      /** @var Pimple $ioc */
      $ioc = Zend_Registry::get("ioc");

      // No IDE assistance for the string "location-service"
      $service = $ioc["location-service"];
   }
}
rodrigo-silveira
  • 12,607
  • 11
  • 69
  • 123
  • But ... PhpStorm has support for completing array keys, so it should work (depending on how you are using it, actually): http://youtrack.jetbrains.com/issue/WI-4353 . Maybe (just maybe -- have not tested this myself) it does not work because `$ioc` is not pure array but object with ArrayIterator (or similar) interface? – LazyOne Jan 03 '14 at 21:29
  • That's precisely why it doesn't work. PHPStorm even throws a warning (depending on intellisense settings) saying it can't follow dynamically added attributes. – rodrigo-silveira Jan 04 '14 at 01:03
  • So it's because of `ArrayAccess`.. OK. Currently PhpStorm has poor limited support for such stuff ( http://youtrack.jetbrains.com/issue/WI-937 ). Just an idea (not sure how it will work) -- what if you add typehint via PHPDoc stating that this variable is both plain array and instance of Pimple? e.g. `/** @var array|Pimple $ioc */` before `$ioc` initialisation. – LazyOne Jan 04 '14 at 01:23
  • Another tickets to watch after are: 1) http://youtrack.jetbrains.com/issue/WI-17116 and 2) http://youtrack.jetbrains.com/issue/WI-3423 – LazyOne Jan 04 '14 at 01:31
  • In any case-- could you provide some simple code example that I could run few tests on it -- that's if above suggestion would not work, of course. – LazyOne Jan 04 '14 at 01:33
  • I'll try that. Currently I do use phpdoc to specify that $ioc is Pimple, which gives me intellisense on Pimple's methods. But since $ioc is created with 'new Pimple ()' that buys me little. It still won't analyze dynamic attributes (any I add through $ioc['attr_key'] – rodrigo-silveira Jan 04 '14 at 01:34
  • @LazyOne just edited the question and added sample code – rodrigo-silveira Jan 04 '14 at 22:00
  • So .. `$ioc` is a local variable and not some class property defined only once. Yes, this would explain why it does not work as technically `$ioc` in one method/class is **different** to `$ioc` in another method/class. I **personally** do not think that anything can be done here ATM for array keys completion. Maybe when previously mentioned 2 tickets will be implemented (esp WI-17116) it could be possible to do something in this regard. I can only suggest to post your latest example with good description of required functionality as Feature Request ticket on the PhpStorm's Issue Tracker. – LazyOne Jan 04 '14 at 22:37

2 Answers2

2

I currently use the DynamicReturnTypePlugin for PhpStorm and have the following config of it in my dynamicReturnTypeMeta.json:

{
    "methodCalls": [
        {
            "class": "\\MyOwnWrapperOfDIContainer",
            "method": "get",
            "position": 0
        },
        {
            "class": "\\Pimple\\Container",
            "method": "offsetGet",
            "position": 0
        }
    ]
}

This configurations means the following: whenever in code I'm using any variable of type Pimple\Container as an array (this will call its ArrayAccess::offsetGet method), then PhpStorm should consider the return value is of type that was used as a key when accessing that array. i. e.:

$c = new Pimple\Container;
$c['MyClass']->/*here autocompletion works*/methodOfMyClass();

I also use it in that way:

$myClassInstance = MyOwnWrapperOfDIContainer::get(MyClass::class);
$myClassInstance->methodOfMyClass(); // autocompletion works here

The only problem is when you register some dependencies in Pimple container not by their class name, but using other names which you want. E. g., autocompletion won't work in the following case:

$c = new Pimple\Container;
$c['my-favourite-var'] = new MyClass(1);
$c[MyClass::class] = new MyClass(2);
$c['my-favourite-var']->/*here autocompletion doesn't work*/methodOfMyClass();
$c['MyClass']->/*here autocompletion works*/methodOfMyClass();

Still you can workaround it like this:

class MyFavouriteVar extends MyClass;
$c[MyFavouriteVar::class] = new MyFavouriteVar(2);
// or even like this:
$c[MyFavouriteVar::class] = new MyClass(2);
$c[MyFavouriteVar::class]->/*now autocompletion works fine*/methodOfMyClass();

Or you have to find some other solution of your problem...

edit 1

also consider this article: http://confluence.jetbrains.com/display/PhpStorm/PhpStorm+Advanced+Metadata

edit 2

and this plugin https://github.com/Sorien/silex-idea-plugin

edit 3

Also it's possible to workaround the problem mentioned above like this:

class MyPimple extends Pimple\Container
{
    public function get($type, $desc = null) {
        return $this[$type . (isset($desc) ? ':' . $desc : '')];
    }
}
$c = new MyPimple;
$c[MyClass::class] = new MyClass('default');
$c[MyClass::class . ':' . 'my-special-value'] = new MyClass('special');
$c->get(MyClass::class, 'my-special-value')->/*autocompletion should work*/methodOfMyClass();

The dynamicReturnTypeMeta.json should then contain:

{
    "methodCalls": [
        {
            "class": "\\MyPimple",
            "method": "get",
            "position": 0
        }
    ]
}
Anatoly U
  • 258
  • 1
  • 11
0

Put the file ".phpstorm.meta.php" into root of your repository. Content of file .phpstorm.meta.php:

<?php
namespace PHPSTORM_META {
    override( \Container::get(0), map([]));
}

Where \Container::get - method for get some object, example:

\Container::get('My\Super')

or

\Container::get(My\Super::class)

and now you can use autocomplete of all class methods.

Lebnik
  • 628
  • 8
  • 11