Summary
PHPantom works great for standard Composer projects, but projects like Drupal use a custom class loader that bypasses Composer's autoloading entirely. Three small configuration additions would make PHPantom usable for a large class of real-world PHP projects.
Context: How Drupal loads classes
Drupal does not register module namespaces in composer.json. Instead, it discovers modules at runtime by scanning *.info.yml files and dynamically registering PSR-4 namespaces via its own class loader. This means:
vendor/autoload_classmap.php and autoload_psr4.php don't know about any module classes
strategy = "self" works around this, but at the cost of surfacing vendor-internal classes
A more targeted solution would be a combination of the three features below.
Requested features
1. includePaths — additional scan directories
Allow specifying extra directories to scan for classes, on top of what Composer knows about. These would be treated like strategy = "self" but scoped to specific paths.
[indexing]
strategy = "composer"
include_paths = ["web/modules", "web/themes", "web/profiles"]
This mirrors intelephense.environment.includePaths and gives precise control without the downsides of global "self" scanning.
2. fileExtensions — treat non-.php files as PHP
Drupal uses several file extensions for valid PHP files:
| Extension |
Purpose |
.module |
Hook implementations, main module file |
.install |
hook_schema(), update hooks |
.theme |
Theme hook implementations |
.inc |
Shared include files |
These are plain PHP files with a <?php header. PHPantom currently won't index them.
[indexing]
file_extensions = ["php", "module", "install", "theme", "inc"]
3. LSP initializationOptions — editor-side configuration
Currently the only way to configure PHPantom is via .phpantom.toml committed to the repository. It would be useful to also accept configuration through LSP initializationOptions (passed by the editor in initialize request).
Why this matters:
- Editor config (Zed
settings.json, VS Code settings.json, Neovim) is the natural home for developer-specific settings
.phpantom.toml is project-scoped; some settings are developer-scoped
- Avoids committing editor tooling config into the project repo
- Consistent with how Intelephense, clangd, and other LSP servers handle this
The schema could mirror .phpantom.toml but as JSON:
{
"phpantom": {
"php": { "version": "8.3" },
"indexing": {
"strategy": "composer",
"include_paths": ["web/modules", "web/themes"],
"file_extensions": ["php", "module", "install", "theme", "inc"]
}
}
}
.phpantom.toml and initializationOptions could be merged, with the toml file taking precedence for project-level settings.
Who this affects
- Drupal projects (one of the largest PHP ecosystems, ~1M+ sites)
- Legacy codebases using
.inc includes
- Any project with a custom autoloader alongside Composer
Happy to test any of this on a real Drupal codebase and report back.
Summary
PHPantom works great for standard Composer projects, but projects like Drupal use a custom class loader that bypasses Composer's autoloading entirely. Three small configuration additions would make PHPantom usable for a large class of real-world PHP projects.
Context: How Drupal loads classes
Drupal does not register module namespaces in
composer.json. Instead, it discovers modules at runtime by scanning*.info.ymlfiles and dynamically registering PSR-4 namespaces via its own class loader. This means:vendor/autoload_classmap.phpandautoload_psr4.phpdon't know about any module classesstrategy = "self"works around this, but at the cost of surfacing vendor-internal classesA more targeted solution would be a combination of the three features below.
Requested features
1.
includePaths— additional scan directoriesAllow specifying extra directories to scan for classes, on top of what Composer knows about. These would be treated like
strategy = "self"but scoped to specific paths.This mirrors
intelephense.environment.includePathsand gives precise control without the downsides of global"self"scanning.2.
fileExtensions— treat non-.phpfiles as PHPDrupal uses several file extensions for valid PHP files:
.module.installhook_schema(), update hooks.theme.incThese are plain PHP files with a
<?phpheader. PHPantom currently won't index them.3. LSP
initializationOptions— editor-side configurationCurrently the only way to configure PHPantom is via
.phpantom.tomlcommitted to the repository. It would be useful to also accept configuration through LSPinitializationOptions(passed by the editor ininitializerequest).Why this matters:
settings.json, VS Codesettings.json, Neovim) is the natural home for developer-specific settings.phpantom.tomlis project-scoped; some settings are developer-scopedThe schema could mirror
.phpantom.tomlbut as JSON:{ "phpantom": { "php": { "version": "8.3" }, "indexing": { "strategy": "composer", "include_paths": ["web/modules", "web/themes"], "file_extensions": ["php", "module", "install", "theme", "inc"] } } }.phpantom.tomlandinitializationOptionscould be merged, with the toml file taking precedence for project-level settings.Who this affects
.incincludesHappy to test any of this on a real Drupal codebase and report back.