Question

I know that it is possible to use Ctrl+] to jump to a definition in Vim and this can work in conjunction whith either ctags or Cscope. I am looking for a more accurate alternative to both ctags and Cscope when working PHP. Sometimes there are multiple possible results to choose from or false positives. I only want to jump to the actual definition of whatever is under the cursor. Ideally this should work for variables, functions, constants, and classes.

I don't see why this can't be done by analyzing the files. I have finally overcome just about every other annoyance/misunderstanding I have with Vim by learning and customizing, so if I could nail this one it would be awesome.

Also, do other's agree that Cscope and ctags are not accurate enough for PHP or am I doing something wrong?

UPDATE

4 years later, I am still using Vim with PHP, and still having this problem. I have tried eclim, ctags, exubarant-ctags, universal-ctags, and cscope. I have tried passing various arguments to these programs to get them to generate better tags. The experience is very poor for all of these options.

But I understand the problem much better now. There might be nothing wrong with the tags generated by these programs. The problem seems to be that when you press Ctrl + ] in Vim or Neovim, it just looks for a tag by that name. It is not looking at the context of the file you are editing to see which tag by that name it should use. It does not even understand what language you are editing, and look for tags from code in that language.

Is there a way to make vim search through the tags file more intelligently, based on the context, and then jump to the most likely location? You know, like what would happen inside a good IDE?

Was it helpful?

Solution 6

PHP is not a well designed language, and it is not statically typed. As such, the foundation is just not there for any good tools of this kind to be made that would be practical to use in real world projects. IDEs, language servers, and Vim and Neovim plugins can only know as much about the code as the language allows. It is possible to write very consistent code in PHP with as much types as possible and that only utilizes a limited subset of the language, such that tools could understand it. However if your team is capable of writing that good of PHP code, they are good enough to rewrite the code in a more well designed language that can support even better tooling, something like Kotlin which also has great IDE support.

OTHER TIPS

As a C++ developer I had similar issues for a long time. Until, that is, I reorganized my approach to using tag files under Vim a few years ago. The trick that made it work for me was to generate separate tag files for different slices of code: my project, various external code libraries, etc... I then had to set the 'tags' option to look for the files in a priority order, with my local code project files coming first and then working outward from there with the system header files being LAST.

In my case, I had separate tag files for each of these and listed in this order in the 'tags' option:

  1. My local project
  2. Any other project that this project uses
  3. System-bundled libraries (boost)
  4. System-bundled libraries (WxWidgets)
  5. System libraries (C++ standard libraries)
  6. System libraries (all else)

I'm not a PHP developer, but again the main mistake I made for a long time was just generating a single tags file FOR EVERYTHING. I'd have upwards of 30 tags to search through many times (using the :tag command). If you generate multiple tags files you have much more control over the search order of tags and thus what tags in which files are found.

See if that works for you. It did for me.

To improve ctags for PHP, you could create tags file like this:

#!/bin/bash
cd /path/to/framework/library
exec ctags-exuberant -f ~/.vim/mytags/framework \
-h ".php" -R \
--exclude="\.svn" \
--totals=yes \
--tag-relative=yes \
--PHP-kinds=+cf \
--regex-PHP='/abstract class ([^ ]*)/\1/c/' \
--regex-PHP='/interface ([^ ]*)/\1/c/' \
--regex-PHP='/(public |static |abstract |protected |private )+function ([^ (]*)/\2/f/'

then load the tags

:set tags=~/.vim/mytags/framework

taken from my blog post

You may also wanna take a look at eclim.

This could utilize eclipse's completion feature, and it should work fine for PHP (I haven't tried).

Struggled with the same problem for a long time until I found the LanguageServer for PHP.

It provides features like GoToDefinition, ShowReferences, Tags at current document etc. It is integrating okay with fzf right out of the box.

Things I don't like about it:

  1. autocompletion is slow compared to other frameworks like padawan
  2. it doesn't cache (yet) your project's index, which means, it has to reindex when you open neovim. Nevertheless, you can use the GoToDefinition functionality while it's still indexing.

Quick setup for vim-plug:

Plug 'autozimu/LanguageClient-neovim', { 'do': ':UpdateRemotePlugins' }

Plug 'roxma/LanguageServer-php-neovim', {'do': 'composer install && composer run-script parse-stubs'}

autocmd FileType php LanguageClientStart

nnoremap <silent> gd :call LanguageClient_textDocument_definition()<CR>

nnoremap <silent> gr :call LanguageClient_textDocument_references()<CR>

Best solution I've found so far.

More of a workaround, but if you press g CTRL+[ instead of just CTRL+', you get a list of all the tags of that name, and you can select which one to jump to.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top