Code completion on type hinted params when the params are Interfaces

Apparently programming to interfaces is good practice, therefore one frequently see's framework code in which methods accept params that are type hinted, and the hinted types are interfaces. That's all good and dandy. PHP runs this kind of code without any issues what so ever, because PHP does not expect you to pass an interface to a method, but an instance of a class implementing the type hinted interface. Now ... why is it that PHPstorm is seemingly incapable of looking just one or two steps further than the hinted type, namely classes which implement said types ?

The reason I'm somewhat frustrated here is, frequently the interaces don't contain all the methods one might want to call. The actual classes often tend to have methods of their own too, and obviously the way things work now, those class methods simply don't exist for PHPstorm, and hence, not only do you get highlighted methods apparently not found, but you can't even use code completion to write / use / call any of those methods.

Is there a setting in PHPstorm that can provide the functionality I am looking for, or does it need to be implemented first ?

I was able to come up with a work-around to this problem, but work-arounds are what they are ... just extra work.

Ofcourse I could change all my imports to use the concrete class everywhere instead of the interface, but I'm not sure if that is going to bite me some day.

1 comment
Comment actions Permalink

Hi there,

If interface (ServerRequestInterface) does not have a method that particular class that implements that interface has (\Slim\Http\Request) ... and you want to call THAT method .. then it's not used correctly. It may work fine because by default it will be an instance of \Slim\Http\Request that has that method implemented .. but you CAN change that (must be possible in Slim container settings; to use different class instead).

Programming via interfaces means that whatever actual instance will be passed (instance of class implements that interface) it will have those interface methods for sure (the main point of interfaces in PHP). And you are trying to call a method (someMethod) that is found in THAT CLASS ONLY and not in interface...

The above means: if you receive an instance of \MyApp\Http\MyRequest instead of usual \Slim\Http\Request, even though they both implement ServerRequestInterface, such call to someMethod will fail (because it's not present in MyRequest class implementation).

 

IDE works correctly here: if parameter is expected to implement specific interface, then it's guaranteed that those methods (declared in interface) will be present (can be called) as that's what interface guarantees (a contract). Other methods may not be available and that depends on actual instance (particular class). If you know that parameter will ALWAYS be of that particular class, then you better use that specific class for typehint and not interface (or use some another methods via PHPDoc).

Simple code to illustrate that. In both callMe() calls actual class instance implements required interface .. but extra method is implemented in one of the classes only.

interface someI
{
public function stdM();
}

class ClassA implements someI
{
public function stdM()
{
echo __METHOD__ . "\n";
}

public function someMethod()
{
echo __METHOD__ . "\n";
}
}

class ClassB implements someI
{
public function stdM()
{
echo __METHOD__ . "\n";
}
}

function callMe(someI $obj)
{
$obj->stdM();
$obj->someMethod();
}

callMe(new ClassA());
callMe(new ClassB());
1

Please sign in to leave a comment.