php-lsp 0.1.13

A PHP Language Server Protocol implementation
php-lsp-0.1.13 is not a library.

php-lsp

A PHP Language Server Protocol (LSP) implementation written in Rust.

Features

Language intelligence

  • Diagnostics — syntax errors reported in real time; semantic warnings for undefined symbols, argument-count mismatches, and undefined variables inside function/method bodies; workspace-wide diagnostics available for all indexed files (not just open ones)
  • Hover — PHP signature for functions, methods, classes, interfaces, traits, and enums (including implements); includes @param/@return/@throws/@deprecated/@see/@link/@template/@mixin docblock annotations when present; deprecated symbols show a > Deprecated banner; built-in PHP functions include a link to the official php.net documentation
  • PHPDoc type system — full docblock support: @param, @return, @var, @throws, @deprecated, @see, @link; @template T / @template T of Base generics; @mixin ClassName; callable type signatures callable(int, string): void parsed correctly
  • Go-to-definition — jump to where a symbol is declared, including across open files and into Composer vendor packages via PSR-4 autoload maps
  • Go-to-implementation — find all classes that implement an interface or extend a class
  • Find references — locate every usage of a symbol across the workspace, including use import statements
  • Rename — rename any function, method, or class across all open files, including its use import statements

Editing aids

  • Completion — keywords, ~200 built-in PHP functions, classes, methods, properties, constants, enums, and enum cases; -> completions scoped to the inferred receiver type ($obj = new Foo()$obj-> shows Foo's and all ancestor instance members); $this-> inside a method resolves to the enclosing class and walks the full inheritance chain; ClassName::/self::/static:: show static members and constants; parent:: shows parent-class static members; funcName( offers named-argument (param:) completions; type inference extends to typed function/method parameters; cross-file symbols from all indexed documents; @mixin ClassName docblock causes mixin members to appear in -> completions; camel/underscore-case fuzzy matching — typing GRF matches getRecentFiles, str_r matches str_replace
  • Signature help — parameter hints while typing a call, including overload narrowing
  • Inlay hints — parameter name labels at call sites; return-type labels after assigned function calls
  • Code actions — "Add use import" quick-fix for undefined class names; PHPDoc stub generation for undocumented functions and methods
  • Document linksinclude/require paths are clickable links to the target file

Navigation

  • Document symbols — file outline of all functions, classes, enums (with cases and methods), methods, properties, and constants
  • Workspace symbols — fuzzy-search symbols across the entire project
  • Call hierarchy — incoming callers and outgoing callees for any function or method, including cross-file
  • Type hierarchy — navigate supertypes and subtypes for classes and interfaces; registered dynamically so all LSP clients discover it correctly
  • Go-to-declaration — jump to the abstract or interface declaration of a method
  • Go-to-type-definition — jump to the class of the type of a variable
  • Selection range — smart expand/shrink selection (Alt+Shift+→) from expression → statement → function/class → file
  • Document highlight — highlights all occurrences of the symbol under the cursor in the current file
  • Folding ranges — collapse functions, classes, methods, loops, and control-flow blocks

Syntax & formatting

  • Semantic tokens — richer syntax highlighting for functions, methods, classes, interfaces, traits, enums, parameters, properties, and PHP 8 #[Attribute] names (highlighted as class references) with declaration/static/abstract/readonly/deprecated modifiers; symbols marked @deprecated render with strikethrough in supporting editors; supports full, range, and incremental delta requests
  • On-type formatting — auto-indents the new line on Enter (copies surrounding indentation, adds one level after {); aligns } to its matching { on keypress
  • Formatting — delegates to php-cs-fixer (PSR-12) or phpcbf; supports full-file and range formatting

Workspace

  • Workspace indexing — background scan indexes all *.php files on startup (including vendor/), with a 50 000-file cap; LRU eviction keeps memory bounded at 10 000 indexed-only files; progress is reported via $/progress so editors display a spinner during the initial scan
  • PSR-4 resolution — reads composer.json and vendor/composer/installed.json to resolve fully-qualified class names to files on demand
  • PHPStorm metadata — reads .phpstorm.meta.php from the workspace root and uses override(ClassName::method(0), map([...])) declarations to infer factory method return types (e.g. $container->make(UserService::class)$user: UserService)
  • File watching — index stays up to date when files are created, changed, or deleted on disk
  • File rename — moving or renaming a PHP file automatically updates all use import statements across the workspace to reflect the new PSR-4 fully-qualified class name (workspace/willRenameFiles)
  • Async parsing — edits are debounced (100 ms) and parsed off the tokio runtime; stale results from superseded edits are discarded

Installation

cargo install php-lsp

Or build from source:

git clone https://github.com/jorgsowa/php-lsp
cd php-lsp
cargo build --release
# binary at target/release/php-lsp

Editor Setup

PHPStorm (2023.2+)

  1. Open Settings → Languages & Frameworks → Language Servers
  2. Click + and configure:
    • Name: php-lsp
    • Language: PHP
    • Command: /path/to/php-lsp
  3. Set file pattern to *.php

Neovim (via nvim-lspconfig)

vim.api.nvim_create_autocmd("FileType", {
  pattern = "php",
  callback = function()
    vim.lsp.start({
      name = "php-lsp",
      cmd = { "/path/to/php-lsp" },
      root_dir = vim.fs.root(0, { "composer.json", ".git" }),
    })
  end,
})

VS Code

Use the custom LSP client extension or any extension that supports arbitrary LSP servers. Set the server command to the php-lsp binary.

How It Works

The server communicates over stdin/stdout using the Language Server Protocol. It uses php-ast (backed by php-rs-parser and a bumpalo arena) to parse PHP source into an AST, which is cached per document and reused across all requests.

License

MIT