A high-performance PHP language server written in Rust.
Docs site · Getting Started · Features · Editors & AI Clients · Configuration · Architecture · Contributing
php-lsp is a full-featured LSP implementation for PHP: real-time cross-file diagnostics, type-aware completions, navigation, and refactoring — written in Rust for low memory usage, fast startup, and zero GC pauses.
Unique strengths:
- Full LSP 3.17 specification support — call hierarchy, type hierarchy, semantic tokens, inlay hints, selection range, linked editing, and more — features that competing servers lock behind premium tiers or skip entirely
- Rich code actions — 10 actions (extract variable/method/constant, inline variable, generate constructor/getters/setters, implement missing methods, organize imports, add PHPDoc, add return type), all free
- Clean separation of concerns — parsing (php-rs-parser, php-ast) and static analysis (mir-php) are dedicated crates, keeping the LSP layer lightweight and focused purely on protocol features
- Rust-native performance — async-first with tokio, lock-free document store via dashmap, no GC pauses
- Completion depth — type-aware
->/::chains,matchenum-case completions, autouseinsertion, fuzzy camel/underscore matching - Layered diagnostics, not a fork in the road — the built-in
mir-backed analyzer works out of the box with zero configuration; a project's own PHPStan/PHPCS setup can be layered on top as an opt-in overlay (externalTools) rather than a replacement, so adopting one doesn't mean giving up the other - Laravel-aware — route/view/translation/env/asset string-key completion and navigation,
->middleware(...)alias resolution, plus quickfixes for missing routes, facade-to-dependency-injection conversion, and unguarded mass assignment;$requestfield completion and validation-rule generation round out request handling - Blade template support — completion, hover, go-to-definition and document links for
route()/view()/config()/asset()/env()/trans()inside{{ }}/{!! !!}expressions,@include/@extends/@each/@component/@livewiredirectives, and<x-alert>/<x-forms.input>/<livewire:counter>component tags — resolving anonymous Blade components and Livewire view-only components throughresources/views, and falling back to class-basedApp\View\Components\*/App\Livewire\*components when no matching view exists
cargo install php-lspOr download a pre-built binary (macOS, Linux) from Releases and place it on your PATH.
On NixOS or with Nix installed:
nix run github:jorgsowa/php-lspVerify:
php-lsp --versionFor full installation options see Getting Started.
| Editor | Setup |
|---|---|
| VS Code | php-lsp extension (source) |
| Neovim 0.11+ | Native vim.lsp.enable |
| Neovim 0.10 | vim.lsp.start in a FileType autocmd |
| Zed | lsp block in ~/.config/zed/settings.json |
| Cursor | Settings → Features → Language Servers |
| PHPStorm | php-lsp plugin (source) |
| Claude Code | claude plugin marketplace add https://github.com/jorgsowa/claude-php-lsp-plugin then claude plugin install php-lsp |
| OpenCode | lsp block in opencode.json |
Config snippets for every editor: Editors & AI Clients
Pass options via initializationOptions:
{
"phpVersion": "8.2",
"excludePaths": ["cache/*", "storage/*"],
"diagnostics": {
"deprecatedCalls": false
}
}phpVersion is optional — the server auto-detects it in priority order: config.platform.php in composer.json (explicit platform pin), then the php binary on $PATH (actual runtime), then require.php in composer.json (compatibility range, last resort), then defaults to 8.5. The detected version and its source are logged on startup. Set phpVersion explicitly to override, e.g. when running PHP inside Docker.
See Configuration for all options including per-diagnostic toggles.
See CONTRIBUTING.md. Open an issue before starting non-trivial work. PRs require clean cargo test and cargo clippy -- -D warnings.