PHPantom — Roadmap¶
This document tracks planned work for PHPantom. Each item links to a domain document with full context. Items are grouped into time-boxed sprints (roughly 1-2 weeks each) and a backlog of ideas not yet scheduled.
Guiding priorities: Completion accuracy → Type intelligence → Cross-file navigation → Diagnostics → Code actions → Performance.
Items inside each sprint are ordered by priority (top = do first): low-complexity items (easiest to assign, least implementation risk) before heavy lifts, dependencies before their dependents, and within the same complexity tier by impact descending. The backlog is ordered by impact (descending), then complexity (ascending) within the same impact tier.
Complexity measures how hard the task is to implement correctly, not how long it takes (time estimates are consistently wrong; skill required is not). Use it to decide who to assign: a Low-complexity item (e.g. adding a hundred repetitive docblock tags) is safe for a low-skill contributor even if it's tedious; a High-complexity item (e.g. a 50-line change to the forward walker) needs an experienced contributor even though it's short.
| Label | Scale |
|---|---|
| Impact | Critical, High, Medium-High, Medium, Low-Medium, Low |
| Complexity | Low (mechanical/boilerplate, no design decisions), Medium (self-contained, follows an existing pattern), Medium-High (spans modules, some new design), High (shared/core subsystem, correctness or performance tradeoffs), Very High (cross-cutting architecture, wide blast radius) |
Scheduled Sprints¶
Sprint 6 — 0.10.0 release, full indexing¶
| # | Item | Impact | Complexity |
|---|---|---|---|
| Release 0.10.0 |
Sprint 7 — 1.0 release & IDE extensions¶
| # | Item | Impact | Complexity |
|---|---|---|---|
| Clear refactoring gate | — | — | |
| E1 | External stub packages (ide-helper, etc.) | Medium-High | Low |
| E5 | Extension stub coverage audit | Medium | Low |
| E4 | Embedded stub override with external stubs (depends on E1) | Medium | Low |
| E3 | IDE-provided and .phpantom.toml stub paths (depends on E2) |
Low-Medium | Low |
| D10 | PHPMD diagnostic proxy | Low | Medium |
| L1 | Facade completion (upstream facade-documenter PRs) |
High | High |
| E2 | Project-level stubs as type resolution source (depends on E1) | Medium | High |
| F20 | Migrate to the maintained tower-lsp fork |
Low-Medium | Very High |
| F21 | Static typeHierarchyProvider advertisement (depends on F20; also needs an upstream lsp-types fix) |
Low-Medium | Low |
| Release 1.0.0 + IDE extensions |
Sprint 8 — Blade support¶
| # | Item | Impact | Complexity |
|---|---|---|---|
| Clear refactoring gate | — | — | |
| BL23 | Unbalanced component tag diagnostics | Low-Medium | Medium |
| BL14 | Folding ranges for Blade files | Low-Medium | Medium |
| BL24 | Named slot variables scoped to the component that receives them | Low-Medium | Medium |
| BL17 | format --check CLI subcommand for CI (depends on BL16) |
Low-Medium | Medium |
| BL1 | Blade-aware code actions | Medium | Medium-High |
| BL15 | Document outline (symbols) for Blade files | Low-Medium | Medium-High |
| BL16 | Blade-aware formatting | Low-Medium | High |
Backlog¶
Items not yet assigned to a sprint. Worth doing eventually but unlikely to move the needle for most users.
| # | Item | Impact | Complexity |
|---|---|---|---|
| Completion | |||
| C1 | Array functions needing new code paths | Medium | High |
| C11 | Smarter member ordering after -> / :: |
Medium | High |
| C8 | Filesystem proximity as an affinity tiebreaker | Low-Medium | Medium |
| C3 | Go-to-definition for array shape keys via bracket access | Low-Medium | Medium |
| C7 | class_alias() support |
Low-Medium | Medium-High |
| C5 | #[ReturnTypeContract] parameter-dependent return types |
Low | Medium |
| C6 | #[ExpectedValues] parameter value suggestions |
Low | Medium |
| C10 | Deprecation markers on class-name completions from all sources | Low | Medium |
| C12 | The implicit $value of a set hook is not offered by variable completion |
Low | Medium |
| C4 | Non-array functions with dynamic return types | Low | High |
| Type Inference | |||
| T20 | Type narrowing reconciliation engine (CNF clause algebra, sure/sureNot tracking) | Medium-High | Very High |
| T41 | @param-out is parsed but never read |
Medium | Medium |
| T28 | Template inference depth priority (shallowest bound wins) | Medium | Medium-High |
| T3 | Property hooks (PHP 8.4) | Medium | Medium-High |
| T34 | static::CONST over-narrows to the declaring class's value |
Medium | Medium-High |
| T29 | Definite vs possible variable existence tracking | Medium | High |
| T30 | Literal type collapse limit | Low-Medium | Medium |
| T40 | pathinfo() returns a shape or a string depending on the flags argument |
Low-Medium | Medium |
| T26 | Globbed constant unions (Foo::BAR_*) |
Low-Medium | Medium |
| T33 | Class constant on an expression ($obj::CONST) resolves to nothing |
Low-Medium | Medium |
| T6 | Closure::bind() / Closure::fromCallable() return type preservation |
Low-Medium | Medium-High |
| T13 | Closure variables lose callable signature detail | Low-Medium | Medium-High |
| T31 | Closure literal-return shape inference | Low-Medium | Medium-High |
| T4 | Non-empty-* type narrowing and propagation | Low-Medium | High |
| T5 | Fiber type resolution | Low | Medium |
| T10 | Ternary expression as RHS of list destructuring | Low | Medium |
| T11 | Nested list destructuring | Low | Medium |
| Bugs | |||
| B218 | new ReflectionProperty(Foo::class, 'bar') forgets what it reflects |
Low | Medium |
| B226 | A function-static variable's type is not tracked across its own reads |
Low-Medium | Medium-High |
| Diagnostics | |||
| D6 | Unreachable code diagnostic | Low-Medium | Medium |
| D16 | unreachable_match_arm ignores literal subject types |
Low-Medium | Medium |
| D5 | External tool diagnostic suppression actions | Low | Low |
| D15 | Unused parameter diagnostic | Low | Medium |
| D17 | docblock_native_mismatch only judges nullability |
Low | Medium-High |
| D18 | array<int, T> is accepted wherever a list<T> is declared |
Low | Medium-High |
| Code Actions | |||
| A40 | Generate method from call | Medium-High | Medium-High |
| A28 | Explicit nullable parameter type (PHP 8.4 deprecation) | Medium | Low |
| A16 | Snippet placeholder for extracted method name (lets the user type over the generated name immediately) | Medium | Medium |
| A46 | Honor context.only in code action responses |
Medium | Medium |
| A25 | strpos → str_contains (PHP 8.0+) |
Medium | Medium |
| A41 | Create class from non-existing name | Medium | Medium-High |
| A34 | Unified code action handler architecture (closure-based resolve, unified fix type) | Medium | Very High |
| A29 | Simplify boolean return (if (cond) return true; return false; → return cond;) |
Low-Medium | Medium |
| A45 | Simplify with ?: (replace $x ? $x : $y with $x ?: $y) |
Low-Medium | Medium |
| A31 | Remove always-else (extract guard clause) | Low-Medium | Medium-High |
| A37 | Simplify with ?-> (replace null-checked chains with the nullsafe operator) |
Low-Medium | Medium-High |
| A38 | Convert if/elseif chain to switch | Low-Medium | Medium-High |
| A43 | Update docblock generics | Low | Medium |
| PHPStan Code Actions | |||
| H4 | assign.byRefForeachExpr — unset by-reference foreach variable |
Medium | Medium |
| H13 | property.notFound — declare missing property (same-class) |
Medium | Medium |
| H15 | Template bound from tip — add @template T of X |
Medium | Medium |
| H16 | match.unhandled — add missing match arms |
Medium | Medium-High |
| H19 | property.unused / method.unused — remove unused member |
Low | Low |
| H23 | instanceof.alwaysTrue — remove redundant instanceof check |
Low | Low |
| H24 | catch.neverThrown — remove unnecessary catch clause |
Low | Low |
| H20 | generics.callSiteVarianceRedundant — remove redundant variance annotation |
Low | Medium |
| CLI Fix Rules | |||
| FX7 | add_return_type — generate @return docblocks from function bodies |
Medium-High | Medium-High |
| FX1 | deprecated — replace deprecated symbol usage |
Medium | Low |
| FX3 | phpstan.return.unusedType — remove unused type from return union |
Medium | Low |
| FX4 | phpstan.missingType.iterableValue — add @return with iterable type |
Medium | Low |
| FX2 | unused_variable — remove unused variables |
Medium | Medium |
| FX5 | phpstan.property.unused / phpstan.method.unused — remove unused member |
Low | Low |
| FX6 | phpstan.generics.callSiteVarianceRedundant — remove redundant variance |
Low | Medium |
| LSP Features | |||
| F11 | VS Code extension | High | Medium-High |
| F12 | IntelliJ / PHPStorm plugin | High | Medium-High |
| F13 | Homebrew formula | Medium | Low |
| F17 | Wire class move to workspace/willRenameFiles |
Medium | Medium |
| F5 | Call hierarchy (incoming/outgoing calls) | Medium | Medium |
| F2 | Partial result streaming via $/progress |
Medium | Medium-High |
| F7 | Evaluatable expression support (DAP integration) | Low-Medium | Low |
| F15 | Go-to-declaration | Low-Medium | Low |
| F14 | Helix upstream PR (depends on F13) | Low-Medium | Low |
| F16 | On-type } brace de-indent |
Low | Low |
| F19 | Connect to a remote/TCP language server | Low | Medium |
| Signature Help | |||
| S2 | Closure / arrow function parameter signature help | Medium | Medium |
| S3 | Multiple overloaded signatures | Medium | Medium-High |
| S4 | Named argument awareness in active parameter | Low-Medium | Medium |
| S5 | Language construct signature help and hover | Low | Medium |
| Laravel | |||
| L24 | Translation depth: JSON lang files, locales, placeholders | Medium-High | Medium-High |
| L46 | ->can() on a user model the receiver does not name |
Medium-High | Medium-High |
| L30 | Eloquent attribute-array key completion | Medium | Medium |
| L32 | Config-backed named-resource strings (log channels, cache stores, guards, connections, rate limiters) | Medium | Medium |
| L49 | Unguarded Eloquent mass assignment diagnostic | Medium | Medium |
| L17 | Additional string contexts without booting (middleware, assets, validation, Inertia) | Medium | Medium-High |
| L25 | Storage disk name strings | Low-Medium | Low |
| L31 | String-key rename, highlight, and semantic tokens | Low-Medium | Medium |
| L42 | Morph alias completion in array positions | Low-Medium | Medium |
| L3 | $dates array (deprecated) |
Low-Medium | Medium |
| L12 | HasUuids / HasUlids trait — $id typed as string |
Low-Medium | Medium |
| L44 | Sibling resource registrations and degenerate resource names | Low-Medium | Medium |
| L50 | "Create route" quick-fix for an unresolved route name | Low-Medium | Medium |
| L47 | Morph aliases in *_type column comparisons |
Low-Medium | Medium-High |
| L8 | withSum/withAvg/withMin/withMax aggregate properties |
Low-Medium | High |
| L45 | *_count properties are offered on every relationship |
Low-Medium | High |
| L29 | Livewire and Volt component names (Livewire projects only) | Low | Low |
| L27 | Legacy Controller@method action strings |
Low | Low |
| L10 | View::withX() / RedirectResponse::withX() dynamic methods |
Low | Medium |
| L39 | Unused view and translation key detection | Low | Medium |
| L51 | "Convert facade call to dependency injection" refactor | Low | Medium |
| Blade | |||
| BL11 | Custom directive discovery (Blade::directive() / Blade::if() registrations) |
Medium | Medium |
| External Stubs | |||
| E7 | Stub-based framework patches | Medium | Medium-High |
| E6 | Stub install prompt for non-Composer projects | Low | Medium |
| Performance | |||
| P16 | Pre-parsed stub format (eliminate raw PHP embedding) | High | Very High |
| P35 | Diagnostic passes reach only a fraction of available cores | Medium-High | Very High |
| P30 | Evaluate migrating parse/resolve/docblock pipeline to mago-hir (parked — re-evaluated at mago 1.46.0, still no mago-hir consumers upstream) |
Medium-High | Very High |
| P52 | The diagnostic benchmarks measure a path no consumer takes | Medium | Low |
| P53 | The deprecated collector deep-copies a class per member access | Medium | Low |
| P51 | CI-gated scaling and memory invariants | Medium | Low-Medium |
| P17 | mago-names resolution on the parse hot path |
Medium | High |
| P18 | Subtype result caching (per-request HashMap for hierarchy walks) | Medium | High |
| P47 | The resolved-class cache lock caps concurrent class resolution | Medium | Very High |
| P20 | Content-hash gated resolution cache persistence | Medium | Very High |
| P21 | Offset-shifting for cached diagnostics on partial edits | Medium | Very High |
| P3 | Parallel pre-filter in find_implementors |
Low-Medium | Medium-High |
| P50 | Cache the top-level scope for global keyword resolution |
Low-Medium | High |
| P48 | Higher-order collection proxy injection repeats work | Low | Medium |
| P49 | A very long method chain costs superlinear time to analyse | Low | Medium |
| P15 | Two-phase stub index construction (eliminate RwLock on stub maps) |
Low | Medium-High |
| P6 | O(n²) transitive eviction in evict_fqn |
Low | High |
| Indexing | |||
| X7 | Recency tracking | Medium | Medium-High |
| X6 | Disk cache (evaluate later) | Medium | Very High |
| X2 | Parallel file processing — remaining work | Low-Medium | Medium-High |
| X9 | Honor editor file excludes and PHP associations during indexing | Low-Medium | Medium-High |
| Inline Completion | |||
| N1 | Template engine (type-aware snippets) | Medium | Medium |
| N2 | N-gram prediction from PHP corpus | Medium | Very High |
| N3 | Fine-tuned GGUF sidecar model | Medium | Very High |