Using Psalm’s Language Server

Psalm now has built-in Language Server Compatibility support so you can run it in your favourite IDE.

It currently supports diagnostics (i.e. finding errors and warnings), go-to-definition and hover, with limited support for autocompletion (PRs are welcome!).

It works well in a variety of editors (listed alphabetically):

Client configuration

Emacs

I got it working with eglot

This is the config I used:

(when (file-exists-p "vendor/bin/psalm-language-server")
  (progn
    (require 'php-mode)
    (require 'eglot)
    (add-to-list 'eglot-server-programs '(php-mode . ("php" "vendor/bin/psalm-language-server")))
    (add-hook 'php-mode-hook 'eglot-ensure)
    (advice-add 'eglot-eldoc-function :around
                (lambda (oldfun)
                  (let ((help (help-at-pt-kbd-string)))
                    (if help (message "%s" help) (funcall oldfun)))))
    )
  )

PhpStorm

Native Support

As of PhpStorm 2020.3 support for psalm is supported and on by default, you can read more about that here

With LSP

Alternatively, psalm works with gtache/intellij-lsp plugin (Jetbrains-approved version, latest version).

Setup is done via a GUI.

When you install the plugin, you should see a "Language Server Protocol" section under the "Languages & Frameworks" tab.

In the "Server definitions" tab you should add a definition for Psalm:

  • Select Executable
  • Extension: php
  • Path: <path-to-php-binary> e.g. /usr/local/bin/php or C:\php\php.exe
    • this should be an absolute path, not just php
  • Args: vendor/bin/psalm-language-server (on Windows use vendor/vimeo/psalm/psalm-language-server, or for a 'global' install '%APPDATA%' + \Composer\vendor\vimeo\psalm\psalm-language-server, where the '%APPDATA%' environment variable is probably something like C:\Users\<homedir>\AppData\Roaming\)

In the "Timeouts" tab you can adjust the initialization timeout. This is important if you have a large project. You should set the "Init" value to the number of milliseconds you allow Psalm to scan your entire project and your project's dependencies. For opening a couple of projects that use large PHP frameworks, on a high-end business laptop, try 240000 milliseconds for Init.

Sublime Text

I use the excellent Sublime LSP plugin with the following config(Package Settings > LSP > Settings):

    "clients": {
        "psalm": {
            "command": ["php", "vendor/bin/psalm-language-server"],
            "selector": "source.php | embedding.php",
            "enabled": true
        }
    }

Vim & Neovim

ALE

ALE has support for Psalm (since v2.3.0).

let g:ale_linters = { 'php': ['php', 'psalm'] }

vim-lsp

I also got it working with vim-lsp

This is the config I used (for Vim):

au User lsp_setup call lsp#register_server({
     \ 'name': 'psalm-language-server',
     \ 'cmd': {server_info->[expand('vendor/bin/psalm-language-server')]},
     \ 'allowlist': ['php'],
     \ })

coc.nvim

It also works with coc.nvim.

Add settings to coc-settings.json:

  "languageserver": {
    "psalmls": {
      "command": "vendor/bin/psalm-language-server",
      "filetypes": ["php"],
      "rootPatterns": ["psalm.xml", "psalm.xml.dist"],
      "requireRootPattern": true
    }
  }

VS Code

Get the Psalm plugin here (Requires VS Code 1.26+):

Running the server in a docker container

Make sure you use --map-folder option. Using it without argument will map the server's CWD to the host's project root folder. You can also specify a custom mapping. For example:

docker-compose exec php /usr/share/php/psalm/psalm-language-server \
   -r=/var/www/html \
   --map-folder=/var/www/html:$PWD