[PhpStorm] Get All FQN class Names
Hi, is there any way to get a list (or search on) with the FQN from classes?
Currently I'm using:
PhpIndex.getAllClassNames
But that returns only the simplified name.
I think I can build my own index, but it feels like overkill if there is already some implemented solution
Thanks !!
Please sign in to leave a comment.
Hi Enrique,
Depending on what you want to achieve, your code could look something like this
Basically, you're getting all class names first. Then you need to obtain a class' PsiElement which contains an FQN. Optionally, you can filter by a namespace name and/or obtain interfaces/traits in addition to classes.
Best,
Artem
Hi Artem, yes but that's really slow, I tried that
I need to give autocomplete (where prefixMatcher could be just one char, or even empty), so I need to search all classes, that's overkill, should be a faster solution, I can only think in implementing my own index, but I was expecting somethin already present in PhpStorm, when we use CTRL+N (go to class action) it searches with namespaces too...
I really doubt maintaining your own index will solve performance problems in a long term perspective. We're working hard to keep PhpStorm as fast as possible so there are a lot of optimizations applied especially on these indices as they are considered as core ones. PhpIndex#getAllClassNames is a text-based index so it works extremely fast on its own. PhpIndex#getClassesByName is a stub-based index so it could be slow on the first invocation. Afterward, caches come into play and all further invocations will be significantly faster. As I said, these indices are core what means they're used from a plenty of places. Thus there's a high chance that some other place will warm them up before your code will try to access them. From the other hand, the new index won't be shared across the IDE. Additionally, it'll consume CPU and storage. So I would recommend you to start with the existing solution and consider implementing the new index only when you have a proof that it's not enough fast. By the way, Goto Class (Ctrl+N) uses the same approach I've described in my first post.
In any case, if you have any performance problems, feel free to share CPU snapshots with us. We'll be glad to analyze them and make changes if necessary.
I need to filter all possible FQN, the first time I run the for loop with all class names to get the fqn it takes near 8 seconds, if I run it again it's like 5 and next times like 2 or 3 seconds... which is not so bad, but I was expecting something faster (specially the first time, 8 is too much)
My code is just:
I'm adding that to TextFieldWithAutoCompletion.setVariants()
but the Dialog with that TextField is taking 8 seconds to appear due that
The problem I cannot even filter the class names without getting all of them, because I just have the "simple" name, not FQN, and normally in PHP projects we have a loooot of classes that we don't need (maybe from other frameworks etc) I need to load all of them too.
Is there any special reason to make the index by name instead of fqn? I'm pretty sure you need always the FQN not just the name.
The first thing you should do is to use TextFieldWithAutoCompletion#installProvider instead of TextFieldWithAutoCompletion#setVariants. Implementing TextFieldWithAutoCompletionListProvider will allow you to perform all calculations in a background and don't block the UI thread. It's even better if you override TextFieldWithAutoCompletionListProvider#fillCompletionVariants and add items to CompletionResultSet as soon as they're available. So basically replacing fqnClasses.add(phpClass.getFQN()); with result.addElement(LookupElementBuilder.create(phpClass.getFQN())); will improve UX alot.
> Is there any special reason to make the index by name instead of fqn? I'm pretty sure you need always the FQN not just the name.
The thing is that you need both of them. As I said, Ctrl+N uses this approach. You never type an FQN there, right? You type a class name to get a result. The result in its turn is filtered by a namespace if you provide it. Completion works in the same way. And again, as I've already mentioned maintaining several indices is expensive in terms of CPU consumption and storage. Thus it's better to cover existing ones with caches what we did.
Hi Artem, thanks for the tips, but I think I didn't understand them.
What is the difference between using installProvider and setVariants?
I mean, the block is due the time it takes to get all the FQN, this is my code:
I'm already using a custom "provider" but the block is due I process all FQN in constructor, it should be the same if I use setVariants or installProvider (is already installed in my code) in constructor.
I can move the code to another place instead of constructor, but that won't save us from the 8 seconds right?
On the other side, if I move the code inside "fillCompletionVariants" do I need to cache that? because it looks that method will be executed every time the prefix changes. And what about the fillCompletionVariants from the parent?
Do you mean something like this? I'm confused about why this would run faster:
Lastly, I think we always search classes by FQN in PHP, I mean if the project is using namespaces and PSR-0 then the real class name is actually the full FQN, not the class name itself. PHP projects with namespaces usually have a lot of classes with the same name (Product, List, Model, etc) without typing part of the namespace is impossible to find the correct one, that's why I'm implementing a new TextField, is a bit annoying and slow to type the namespace with the "\" character etc