PHPantom is a language server, but it also ships CLI tools for batch analysis and automated fixing. These run the same engine that powers the editor, so results are consistent between what you see in your editor and what CI reports.
| Command | Purpose |
|---|---|
phpantom_lsp |
Start the LSP server over stdin/stdout (the default) |
phpantom_lsp --tcp 9257 |
Start the LSP server listening on a TCP port |
phpantom_lsp analyze |
Report diagnostics across the project |
phpantom_lsp fix |
Apply automated code fixes across the project |
phpantom_lsp init |
Generate a default .phpantom.toml config file |
Running with no subcommand starts the language server. Editors launch this automatically.
By default PHPantom communicates over stdin/stdout, which is what most
editors expect. The --tcp flag switches to TCP transport instead,
which is useful when you want to attach a debugger to the server
process, connect from an IDE plugin that prefers a network socket, or
just poke at the JSON-RPC stream with nc or socat.
The server binds to the given address, accepts a single client connection, serves it, and exits when the client disconnects.
phpantom_lsp --tcp 9257 # listen on 127.0.0.1:9257
phpantom_lsp --tcp 127.0.0.1:9257 # same, explicit host
phpantom_lsp --tcp 0.0.0.0:9257 # listen on all interfaces
phpantom_lsp --tcp 0 # OS picks a free portWhen the server starts it prints the bound address to stderr:
PHPantom LSP listening on tcp://127.0.0.1:9257
This is especially handy with port 0: the OS assigns an available
port and the server tells you which one it picked.
Any LSP client that supports TCP can connect. For quick manual testing:
# In one terminal, start the server:
phpantom_lsp --tcp 9257
# In another terminal, connect and send JSON-RPC:
nc 127.0.0.1 9257| Flag | Description |
|---|---|
--tcp <ADDR> |
Address to listen on. Full HOST:PORT or just PORT (defaults to 127.0.0.1). |
Scans PHP files and reports PHPantom diagnostics in a PHPStan-style table format. The goal is full symbol resolution: every class, member, and function call in your codebase should be resolvable. When that holds, completion and hover work everywhere, and PHPStan gets the type information it needs at every level.
Use it to find and fix the spots where the editor can't resolve a symbol, so you can achieve and maintain full type coverage across the project.
It doesn't try to find every possible bug. Its main focus is symbol resolution: every class, member, and function call should point to something real. It also catches basic correctness issues like wrong argument counts and missing interface implementations. When a codebase passes cleanly, completions work everywhere for every developer on the team.
That makes it useful in a few situations:
- Teams that just want completions to work in their editor. If
your goal is "every
->and::resolves to something" rather than "catch every possible runtime error," PHPantom's analysis covers exactly that. - As a companion to PHPStan at a moderate level. A team running PHPStan at level 4 (catching dead code and type mismatches) can add PHPantom's analysis to enforce that every class, member, and function is resolvable across the full codebase. PHPStan catches logic errors, PHPantom catches structural gaps. Together they cover a useful quality surface without the effort of configuring PHPStan at max level.
- As a quick sanity check. Point it at a Composer project and it
reports what it finds. No baselines, no ignore files, no level to
choose. The only configuration worth knowing about is
unresolved-member-access: enable it in.phpantom.tomlto also flag member access on variables whose type could not be resolved (off by default because it is noisy on untyped codebases).
Note
There are still occasional false positives, though they are getting fewer with each release. If you hit one, please report it.
phpantom_lsp analyze # scan entire project
phpantom_lsp analyze src/ # scan a subdirectory
phpantom_lsp analyze src/Foo.php # scan a single file
phpantom_lsp analyze --severity warning # errors and warnings only
phpantom_lsp analyze --severity error # errors only
phpantom_lsp analyze --project-root /path/to/app # explicit project root
phpantom_lsp analyze --no-colour # plain text output| Flag | Description |
|---|---|
[PATH] |
File or directory to analyze. Defaults to the entire project. |
--severity <LEVEL> |
Minimum severity: all (default), warning, or error. |
--project-root <DIR> |
Project root directory. Defaults to the current working directory. |
--no-colour |
Disable ANSI colour output. |
| Code | Meaning |
|---|---|
| 0 | No diagnostics found |
| 1 | Diagnostics were found |
------ -------------------------------------------
Line src/Service/UserService.php
------ -------------------------------------------
15 Unknown class 'App\Models\LegacyUser'.
🪪 unknown_class
42 Call to undefined method Post::archive().
🪪 unknown_member
------ -------------------------------------------
The analyze command reports the same diagnostics you see in your editor. Each has a rule identifier shown below the message.
| Identifier | Severity | Description |
|---|---|---|
syntax_error |
Error | PHP parse errors |
unknown_class |
Warning | Class, interface, trait, or enum not resolvable |
unknown_member |
Warning | Property or method not found on the resolved class |
unknown_function |
Error | Function call not resolvable |
argument_count |
Error | Wrong number of arguments to a function or method |
implementation_error |
Error | Missing required interface or abstract methods |
scalar_member_access |
Error | Member access on a scalar type (int, string, etc.) |
unused_import |
Hint | use statement with no references in the file |
deprecated |
Hint | Reference to a @deprecated symbol |
Applies code fixes across the project. Specify which rules to run, or
omit --rule to run all preferred native fixers.
This is useful for cleaning up an entire codebase in one pass. For
example, a project with hundreds of unused use statements can be
cleaned up in seconds rather than file by file.
phpantom_lsp fix # apply all preferred fixers
phpantom_lsp fix --rule unused_import # only remove unused imports
phpantom_lsp fix --rule unused_import --rule deprecated # multiple rules
phpantom_lsp fix --dry-run # preview without writing
phpantom_lsp fix src/ # restrict to a subdirectory
phpantom_lsp fix src/Foo.php # fix a single file
phpantom_lsp fix --project-root /path/to/app # explicit project root| Flag | Description |
|---|---|
[PATH] |
File or directory to fix. Defaults to the entire project. |
--rule <RULE> |
Rule to apply (repeatable). Omit to run all preferred native rules. |
--dry-run |
Report what would change without writing files. |
--with-phpstan |
Enable PHPStan-based fixers (future feature). |
--project-root <DIR> |
Project root directory. Defaults to the current working directory. |
--no-colour |
Disable ANSI colour output. |
| Code | Meaning |
|---|---|
| 0 | Fixes applied successfully (or nothing to fix) |
| 1 | Error (bad arguments, write failure, etc.) |
| 2 | Dry-run found fixable issues (nothing written) |
Rules correspond to diagnostic identifiers.
| Rule | Description |
|---|---|
unused_import |
Remove unused use statements |
------ -------------------------------------------
Line src/Service/UserService.php
------ -------------------------------------------
5 Unused import 'App\Models\LegacyUser'
🔧 unused_import
6 Unused import 'App\Support\OldHelper'
🔧 unused_import
------ -------------------------------------------
[FIXED] Applied 2 fixes across 1 file
phpantom_lsp fix --dry-run --project-root /path/to/app ------ -------------------------------------------
Line src/Service/UserService.php
------ -------------------------------------------
5 Unused import 'App\Models\LegacyUser'
🔧 unused_import
------ -------------------------------------------
[DRY RUN] 1 fix in 1 file (not applied)
Running fix twice produces the same result as running it once. If
all issues are already resolved, the command exits with code 0 and
writes nothing.
Creates a default .phpantom.toml in the current directory with all
options documented and commented out. Safe to run if the file already
exists (it will not overwrite).
phpantom_lsp initSee Project Configuration for details on available settings.
PHPantom works well as a lightweight CI gate. It's a single static binary with no runtime dependencies (no PHP, no Composer, no Node). Drop it into a pipeline and point it at your project root.
Editor diagnostics only help the developer who has the editor open. CI analysis protects the whole team: no PR can merge if it introduces an unresolvable symbol, regardless of which editor each developer uses. Over time this keeps the codebase fully navigable, so completions, hover, and go-to-definition work everywhere for everyone.
It also complements PHPStan rather than replacing it. PHPStan is better at catching logical errors, type mismatches, and dead code. PHPantom is better at catching structural gaps: unknown classes, unresolvable members, missing implementations. Running both gives you broad coverage without needing PHPStan at max level to get full symbol resolution.
name: Type Coverage
on: [push, pull_request]
jobs:
phpantom:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Use --no-dev to catch production code that depends on dev-only
# packages (e.g. calling PHPUnit classes from application code).
- name: Install Composer dependencies
run: composer install --no-interaction --prefer-dist --no-dev
- name: Install PHPantom
run: |
curl -sL https://github.com/AJenbo/phpantom_lsp/releases/download/0.6.0/phpantom_lsp-x86_64-unknown-linux-gnu.tar.gz | tar xz
chmod +x phpantom_lsp
- name: Check type coverage
run: ./phpantom_lsp analyze --severity warning --no-colour src/The analyze step fails the build if any class, member, or function
cannot be resolved (including unused imports). The output is clean and
readable in the CI log.
Diagnostics gate. Fail the build when PHPantom finds unresolvable symbols:
phpantom_lsp analyze --severity warning --project-root . --no-colourEnforce clean imports. Fail the build when unused imports exist:
phpantom_lsp fix --dry-run --rule unused_import --project-root . --no-colourPre-commit hook. Clean up imports before every commit:
phpantom_lsp fix --rule unused_import --project-root .Combine analyze and fix. Run fixes first, then check what remains:
phpantom_lsp fix --project-root .
phpantom_lsp analyze --project-root .