Skip to content

Feature Request: Support indexing classes under symlinked directories (e.g. framework source linked into the project) #383

Description

@liudashuang

Description

PHPantom cannot resolve/parse classes that live under a symlinked directory inside the workspace. Many real-world projects do not use Composer and instead link their in-house framework into the project via a symlink (for example a framework directory pointing to a shared framework checkout elsewhere on disk). Because PHPantom's workspace walk does not follow symlinks, every class under that directory — in our case a whole set of framework namespace prefixes — is missing from the index, so goto-definition / hover / diagnostics fail on those symbols.

Use case

Our project (a PHP 8.3 app) has no composer.json. The framework lives outside the repo and is linked into the project root:

my_project/                <- workspace root (LSP opened here)
├── .phpantom.toml
├── src/                   <- application code (indexed fine)
└── framework -> /absolute/path/to/shared-framework   <- symlink, NOT followed
    ├── core/              <- framework core classes
    └── shared/ -> /absolute/path/to/another/shared-module   <- nested symlink

With [indexing] strategy = "self" (scan every PHP file in the workspace), all framework classes are unresolved. The .gitignore does not exclude the symlinked directory, so the only reason they're missing is that symlinked directories are skipped during the walk.

Proposed solution

Ideally, one (or both) of:

  1. Follow symlinks in the workspace walk — call .follow_links(true) on the ignore::WalkBuilder in src/classmap_scanner/discovery.rs (walk_roots), with cycle protection (the ignore crate handles symlink loops when following is enabled). This would index the linked framework transparently.
  2. A configurable list of extra index roots / include paths in .phpantom.toml (e.g. [indexing] roots = ["/absolute/path/to/shared-framework"]), so projects can explicitly point PHPantom at framework sources outside (or linked into) the workspace without changing directory layout.

A follow_links(true) option flag under [indexing] (default false, opt-in) would also be a safe middle ground.

Alternatives considered

  • [indexing] strategy = "self" — already used; still does not follow symlinks.
  • Removing the symlink and copying the framework into the repo — undesirable: breaks the shared-framework layout (the same framework tree is shared across multiple projects) and risks affecting runtime autoloading.
  • Opening the framework directory as a separate workspace — cross-workspace references still resolve poorly.
  • .gitignore negation (e.g. !framework) — has no effect, since the walk skips symlinks regardless of gitignore status.

Code example

<?php
// src/Service/SomeService.php
namespace app\Service;

use Vendor\Framework\Core\DB;   // <-- unresolved under the symlinked framework dir
use Vendor\Framework\Shared\Foo; // <-- unresolved

class SomeService
{
    public function run(): void
    {
        $db = DB::connect('db');   // goto-definition / hover do not work
    }
}


---

*Context: PHPantom 0.10.0. Confirmed in source that `walk_roots` in `src/classmap_scanner/discovery.rs` builds the `ignore::WalkBuilder` without `.follow_links(true)`.*

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions