I've come across many questions such as this, but most of the suggested solutions are to just invalidate caches/restart or upgrade to the latest version. These solutions don't even work in every case (including mine). In most questions the OP states this isn't working while someone else reports they can do it with no issue. It seems clear to me this is highly dependent on each individual's configuration/setup and certain things must be in place in order for this feature to work properly.
Obviously it is not working for me, but rather than post a question about how to solve my particular situation, I figured it'd be better to learn how PhpStorm determines usages of function definitions. Hopefully the result will be a list of troubleshooting steps to check should this feature not work for someone beyond "Validate Caches/Restart" and upgrading to the most recent release.
I feel like without knowing how this feature finds usages we are left with just trial and error to see what gets it working. If we knew A and B must be true in order for this feature to work, then we can systematically ensure A and B are in fact true.
For clarity, the issue is this. I have a class with a method ClassA::Method1()
. I compose ClassA
into other classes, ClassB
and ClassC
- each of which make use of ClassA::Method1()
. I'm trying to go to the method definition in ClassA
of Method1
, right click on it, choose "Find Usages" and expect it to report back to me every use of it in the classes ClassB
and ClassC
(or any others which happen to use it).
How does PhpStorm determine usages? Is it based on annotations? Namespaces? Combination of both? Or something else entirely?
I may have figured this out through trial and error. It seems to go by namespaces/type hinting and the PSR-4 standard. However it does not seem like PhpStorm has the capability to find usages of concrete class methods if you're programming to interfaces. Particularly when the concrete class extends an abstract class and implements an interface which extends an interface the abstract class implements. I've developed a gist (with comments) to illustrate this.
https://gist.github.com/dlanz/484c1584b5cbe054b9402bde56afae81
In short, if you're programming to interfaces, you must use "Find Usages" on the interface. If an interface extends another interface and you want to only find usages of the extending interface but for a method it inherited - you're either out of luck, or you must redefine the interfaced method in the extending interface. Or you can just never extend interfaces, but sometimes it makes sense to.