PHPantom LSP

repository·main·Indexed 21 days ago

https://github.com/phpantom-dev/phpantom_lsp

A high-performance, Rust-based Language Server Protocol (LSP) implementation for PHP featuring deep type intelligence. It provides advanced support for Generics, PHPStan annotations, Laravel (Eloquent, Blade, Artisan), and Drupal. Designed for rapid startup and low memory consumption, it offers features such as array shape inference, closure parameter inference, and project-wide diagnostics without requiring a lengthy indexing phase.

Tokens
62.9K
Snippets
128
Records
288
Agent score
76%

What's inside phpantom_lsp

  1. Overview of PHPantom Language Server

    main

    PHPantom is a fast, lightweight PHP language server written in Rust. It is designed to be responsive and memory-efficient, avoiding long indexing phases or heavy disk caching. It is suitable for large codebases, capable of becoming ready in seconds with minimal RAM usage.

    Key Capabilities:

    • Deep Type Intelligence: Supports generics, conditional return types, closure parameter inference, array shapes, and PHPStan types.
    • Laravel Support: Provides intelligence for Eloquent relationships, scopes, accessors, casts, Builder chains, macros, and Blade templates without requiring ide-helper or direct database access.
    • Tool Integration: Integrates with PHPStan, PHPCS, and Mago to surface diagnostics from these tools directly in your editor on save.
    • Refactoring: Supports renaming, extracting methods/functions/variables/constants/interfaces, implementing interface methods, promoting constructor parameters, and modernizing syntax.
    • CLI Tools: Includes analyze for batch diagnostics and fix for automated fixes, useful for CI/CD and bulk cleanup.
  2. Overview of the PHPantom module layout

    main

    The project is organized into functional modules. Key areas include:

    • src/server.rs: Handles LSP protocol (initialize, didOpen, completion, etc.).
    • src/types/: Core data models like ClassInfo and MethodInfo.
    • src/parser/: Converts AST to ClassInfo/FunctionInfo.
    • src/resolution.rs: Manages multi-phase class/function lookups.
    • src/type_engine/: The central engine used to answer "what is the type of this expression?". It is consumed by diagnostics, hover, go-to-definition, and signature help.
    • src/completion/: Orchestrates LSP completion requests.
    • src/diagnostics/: Manages native and external (PHPStan/PHPCS) diagnostic collection.
    • src/blade/: Provides Laravel Blade template support.
  3. Overview of PHPantom CLI modes

    main

    The phpantom_lsp CLI tool operates in several modes depending on the subcommand provided. Running the command without a subcommand starts the Language Server Protocol (LSP) server using the default stdin/stdout transport, which is the standard mode for editor integration.

    CommandPurpose
    phpantom_lspStart the LSP server over stdin/stdout (default)
    phpantom_lsp --tcp <ADDR>Start the LSP server listening on a TCP port
    phpantom_lsp analyzeReport diagnostics across the project
    phpantom_lsp fixApply automated code fixes across the project
    phpantom_lsp initGenerate a default .phpantom.toml config file
    phpantom_lsp
  4. Overview of PHPantom LSP

    main

    PHPantom is a fast, lightweight PHP language server written in Rust. It is designed for high performance, using significantly less RAM and offering much faster startup times compared to other language servers. It features no indexing phase, meaning it is ready to use in seconds without waiting for a full project scan.

    Key characteristics:

    • Fast Startup: Ready in approximately 5 seconds.
    • Low Resource Usage: Uses roughly 360 MB of RAM.
    • Deep Type Intelligence: Supports advanced features like Generics, PHPStan types, and Laravel-specific resolution.
    • Project Awareness: Understands Composer, PSR-4, and Drupal projects out of the box.
  5. PHPantom Laravel Intelligence Features

    main

    This demo project showcases how PHPantom provides context-aware intelligence for the Laravel framework across several domains:

    Eloquent Models

    Supports virtual properties from $fillable, $casts, $attributes, relationships, scopes, accessors, custom collections, and query builder forwarding.

    Model Factories

    Provides convention-based factories with:

    • create() and make() methods returning the model.
    • Synthesized dynamic relationship methods like has{Relationship}() and for{Relationship}() (e.g., BlogAuthor::factory()->hasPosts(3)->create()).
    • trashed() support for models using SoftDeletes.
    • Config & Env: Resolves config('key.name') to its file (e.g., config/app.php) and env('VAR') to .env.
    • Views: Resolves view('name') and View::make('path.to.view') to Blade templates in resources/views/.
    • Routes: Resolves route('name') to the corresponding route definition.
    • Controllers: Supports go-to-definition, hover, rename, and completion for route action strings in [Controller::class, 'method'] and Route::controller(...) groups.
    • Translations: Resolves __('key'), trans('key'), and trans_choice(...) to files in the lang/ directory.

    Artisan Commands

    Provides completion, go-to-definition, and diagnostics for command names used in:

    • Artisan::call('command', [...])
    • Artisan::queue(...)
    • Schedule::command(...)
    • $this->call(...)

    Inside a command class, $this->argument(...) and $this->option(...) provide completion and validation against the command's signature/#[AsCommand] attribute.

  6. Understand PHPantom completion capabilities

    main
    PHPantom provides advanced code completion by handling dynamic return types for built-in PHP functions, extracting information from stub attributes, and providing argument-level intelligence. It uses type-inference infrastructure (including generics, narrowing, and conditional types) to resolve complex types that standard static analysis might miss.
  7. How PHPantom communicates with editors

    main

    PHPantom utilizes the LSP textDocument/inlineCompletion request (proposed in LSP 3.18) to provide ghost-text suggestions.

    For editors that do not yet support this specific LSP feature, PHPantom provides fallback mechanisms:

    • completionItem/resolve using snippet insert text.
    • A custom phpantom/inlineCompletion method.

    When a suggestion is provided, the editor renders the text as dimmed 'ghost text' at the cursor, which the user can accept by pressing Tab.

  8. How PHPantom resolves PHP symbols

    main

    PHPantom is a language server for PHP that provides IDE features like completion, go-to-definition, find references, and diagnostics. It resolves symbols (classes, interfaces, traits, enums, and functions) using a multi-step process:

    1. Parsing: PHP files are parsed into lightweight ClassInfo and FunctionInfo structures (rather than a full AST) to capture necessary IDE metadata.
    2. Caching: Parsed results are stored in an in-memory uri_classes_index keyed by file URI.
    3. Symbol Mapping: A precomputed symbol_maps is built during parsing to enable $O(\log n)$ lookups for go-to-definition and call-site detection for signature help.
    4. Resolution: Symbols are resolved via a multi-phase lookup chain.
    5. Inheritance Merging: Inherited members from parent classes, traits, interfaces, and mixins are merged during the resolution phase.
  9. Prevent property writes from overriding types via __set

    main

    Currently, the type engine records property assignments (e.g., $obj->prop = expr) as overrides to the declared class property hints. This is correct for real properties but incorrect for magic properties handled by __set. Because __set can transform or reroute values, the recorded write type should not override the type resolved via __get.

    Example of the issue:

    /** @template TData of array */
    class DataBag {
        /** @param TData $data */
        public function __construct(private array $data) {}
        /** @return TData[K] */
        public function __get(string $property) { return $this->data[$property]; }
        /** @param TData[K] $value */
        public function __set(string $property, $value) { /* may store anything */ }
    }
    
    /** @extends DataBag<array{a: int, b: string}> */
    class FooBag extends DataBag {}
    
    $foo = new FooBag(["a" => 5, "b" => "hello"]);
    $foo->a = 9;
    $a = $foo->a;   // PHPantom: 9 (Incorrect) | Psalm: int (Correct via __get)

    Resolution Strategy: Do not record a property write if the property is undeclared on the subject's class AND the class declares __set. This allows reads to continue resolving through __get.

  10. Resolve template variable types via the Signature Resolution Chain

    main

    PHPantom uses a prioritized resolution chain to determine the types of variables within a Blade template. This chain aligns with the Bladestan model to ensure consistency between the editor and CI type-checking.

    Priority Order (Highest to Lowest):

    1. Backed component class: Public properties and constructor parameters, merged with the blade-side signature.
    2. @bladestan-signature docblock: The canonical contract defined via a specific marker tag. @var tags within this docblock define the template's variables.
    3. Implicit docblock: The first docblock found before the template code is treated as a signature if no @bladestan-signature is present.
    4. @props: Used for default-value type inference in anonymous components.
    5. mixed: The fallback type if no other source is found.
    6. Call-site inference: (Lowest priority) Types inferred from view() calls (e.g., compact(), ->with()) that reference the template. This is used as a fallback for unannotated projects.
  11. Identify unreachable code diagnostics

    main

    PHPantom identifies code that appears after unconditional control flow exits. These are treated as Hints with the DiagnosticTag::UNNECESSARY tag, which causes editors to dim the text rather than underlining it.

    Scenarios that trigger dimming:

    • Code following a return $x; in the same block.
    • Code following a throw new \Exception().
    • Code following exit(1) or die().
    • Code following continue or break within a loop.
    • Code in both branches of an if/else block where both branches contain a terminating statement (e.g., if (...) { return; } else { return; }).
  12. Understand PHPantom's Type System and `PhpType`

    main

    PHPantom uses a high-performance, hash-consed type system centered around the PhpType handle.

    Key Concepts

    • PhpType: A pointer-sized handle to an interned TypeKind node. This allows structural equality to be checked via simple pointer comparison (PartialEq) rather than expensive structural walks.
    • Interning: All types are routed through an interner in php_type/intern.rs. This ensures that structurally identical types share the same memory allocation, reducing memory overhead.
    • Memory Efficiency: Because types are interned, a type occurrence costs only 8 bytes. The system uses weak references in the interner table so that unused type forms are reclaimed, preventing memory leaks in long-running servers.
    • Usage: To inspect a type, use PhpType::kind(). To create new types, use constructors like PhpType::named, PhpType::nullable, or PhpType::union instead of constructing TypeKind directly. This ensures the pointer and structural notions of equality remain synchronized.

    Data Model Integration

    PhpType is used for all type-carrying fields, including:

    • type_hint and native_type_hint
    • return_type and native_return_type
    • asserted_type
    • template_param_bounds
    • Generics type arguments
    • ResolvedType::type_string