Skip to content

fix(extraction): map PHP include/require to file→file dependency edges (#660)#663

Open
maxmilian wants to merge 1 commit into
colbymchenry:mainfrom
maxmilian:fix/660-php-include-require
Open

fix(extraction): map PHP include/require to file→file dependency edges (#660)#663
maxmilian wants to merge 1 commit into
colbymchenry:mainfrom
maxmilian:fix/660-php-include-require

Conversation

@maxmilian
Copy link
Copy Markdown

Fixes #660.

Procedural / script-style PHP wires files together with include/require, but codegraph's PHP extractor only captured namespace_use_declaration as an import — so include/require(_once) produced zero file→file dependency edges. callers(lib.php) returned 0 for require_once("lib.php"); impact/trace missed the whole file-include graph.

What changed

  • src/extraction/languages/php.ts (+41): capture include / include_once / require / require_once expressions and extract the static string-literal path (single/double quotes, with/without parens). Dynamic forms (include $var, require __DIR__ . '/x', interpolated strings) resolve to null and are skipped.
  • src/resolution/import-resolver.ts (+71): resolve a PHP include path to a file→file imports edge relative to the including file, mirroring the existing C/C++ #include path. Added isPhpIncludePathRef to distinguish include paths (contain / or .) from namespace use symbols (FQN / bare class — which never do).
  • src/resolution/index.ts (+14): a path-shaped include that doesn't resolve to a known project file is left unresolved and does not fall back to the symbol name-matcher (which would otherwise mis-connect inc/db.php to an unrelated db.php elsewhere).

Before / After

Before After
require_once("lib.php") no edge; callers(lib.php) = 0 file→file imports edge; callers(lib.php) includes the caller
require "inc/db.php" (subdir) no edge resolves to inc/db.php
include $var / require __DIR__.'/x' no edge unchanged — skipped (no static path)
namespace use App\Foo\Bar resolved as before unchanged
unresolvable require "inc/db.php" no edge (never mis-connects to a same-named file elsewhere)

Validation

npm test on the changed suites (Node 24.14.0):

  • npx vitest run __tests__/resolution.test.ts56/56 passing (+4 new: include→file e2e, subdirectory resolution, no-mis-connect regression, isPhpIncludePathRef unit test)
  • npx vitest run __tests__/extraction.test.ts -t "#660"3/3 new extraction tests passing (four include/require forms, dynamic-skip, include + namespace-use coexistence)

Note: a full extraction.test.ts run hits a pre-existing V8 Fatal process out of memory: Zone crash (~test 205) during turboshaft JIT compilation of the tree-sitter WASM grammars on Node 24.x — reproduced identically on unmodified main, so it is unrelated to this change. The repo's engines are >=18 <25.

Scope

PHP-only — other languages' extractors and resolvers are untouched (the new resolution branch is gated on language === 'php'). Static literal paths only, matching the issue scope; php.ini include_path is not modeled.

@maxmilian maxmilian marked this pull request as ready for review June 3, 2026 07:42
colbymchenry#660)

PHP's importTypes only captured namespace_use_declaration, so
include/require(_once) — the dependency mechanism in procedural and
script-style PHP — never produced edges. callers, impact, and trace
missed the entire file-include graph; only namespace `use` became a
dependency edge.

Capture the four include/require expression types and emit file→file
imports edges, reusing the path-based resolution that C/C++ #include
already goes through. Only static string-literal paths are resolved
(relative to the including file); dynamic forms (include $var,
require __DIR__ . '/x', interpolated strings) are skipped.

Include PATHS are distinguished from namespace `use` symbols by shape: a
path contains '/' or '.', which PHP identifiers and FQNs never do. A
path-shaped include that doesn't resolve to a known project file is left
unresolved and does NOT fall back to the symbol name-matcher, which would
otherwise mis-connect "inc/db.php" to an unrelated db.php elsewhere — a
wrong edge is worse than a missing one.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@maxmilian maxmilian force-pushed the fix/660-php-include-require branch from 909cc42 to b4bed16 Compare June 3, 2026 16:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[PHP] include/require(_once) not mapped to dependency edges — only namespace use; impact/callers miss the file-include graph

1 participant