Environment
- graphify 0.9.65 (also reviewed 0.9.66/0.9.67 release notes — no PHP member-call resolver mentioned)
- Corpus: a ~52 MB Symfony PHP bundle (11,007 nodes / 32,817 edges after extraction),
--code-only mode
Problem A — PHP member calls are silently dropped
extract.py ships member-call resolvers for Swift, Python, TypeScript, C++, C#, Java… but there is no _resolve_php_member_calls. A PHP call like:
$this->emailSender->prepareAndSendEmail($action);
produces no edge at all. Empirical check on our graph: EmailSender::prepareAndSendEmail has 0 incoming edges from other files while at least two services call it — all 18 of its incoming calls edges are intra-file self-calls.
Notably, the cross-repo parking mechanism already exists (_park_unresolved_member_call -> metadata.unresolved_calls, ref #3152) but is never invoked for PHP. Our full graph contains zero parked entries with "lang": "php" — the calls are dropped with no trace instead of being parked.
Problem B — builtins get mis-wired to same-name internal methods
_rewire_unique_stub_nodes rebinds a call to the single internal method sharing the callee's name. PHP language builtins collide with that rule:
- ~200 calls to
empty() (language construct) across ~150 files are wired to an internal method ParseCollectionPaginator::empty() — including 24 false edges from two god-node services alone.
- Same risk class for common names:
execute, handle, format.
So the graph is wrong in both directions: missing edges on real inter-class calls, polluted edges on builtin names.
Impact on a real corpus
A local post-processor (tree-sitter-php, same parking format) recovered on this single bundle:
- -454 false edges removed (builtin rewiring)
- +1,566 real edges added (typed-property member calls, interface -> implementations)
- 6,558 calls parked in
metadata.unresolved_calls (previously dropped silently)
Suggested fix
- Add a PHP member-call resolver: receiver type from typed/promoted constructor properties +
$this->method() self-calls; interface calls -> all implementations.
- Park unresolved PHP member calls in
metadata.unresolved_calls (same payload format as other languages, "lang": "php") so merge-graphs can finish the edges.
- Never rewire a builtin callee name (
empty, count, strlen, ...) to an internal method — consult a builtin list per language before rewiring.
Repro
Any PHP corpus containing $this->someTypedProperty->method(): the edge is absent from graph.json and nothing appears in metadata.unresolved_calls for the caller. Then add a second method named empty anywhere in the corpus and observe empty() calls being wired to it.
Happy to share our local post-processor (pure post-processing on graph.json, idempotent) if useful as a reference implementation.
Environment
--code-onlymodeProblem A — PHP member calls are silently dropped
extract.pyships member-call resolvers for Swift, Python, TypeScript, C++, C#, Java… but there is no_resolve_php_member_calls. A PHP call like:produces no edge at all. Empirical check on our graph:
EmailSender::prepareAndSendEmailhas 0 incoming edges from other files while at least two services call it — all 18 of its incomingcallsedges are intra-file self-calls.Notably, the cross-repo parking mechanism already exists (
_park_unresolved_member_call->metadata.unresolved_calls, ref #3152) but is never invoked for PHP. Our full graph contains zero parked entries with"lang": "php"— the calls are dropped with no trace instead of being parked.Problem B — builtins get mis-wired to same-name internal methods
_rewire_unique_stub_nodesrebinds a call to the single internal method sharing the callee's name. PHP language builtins collide with that rule:empty()(language construct) across ~150 files are wired to an internal methodParseCollectionPaginator::empty()— including 24 false edges from two god-node services alone.execute,handle,format.So the graph is wrong in both directions: missing edges on real inter-class calls, polluted edges on builtin names.
Impact on a real corpus
A local post-processor (tree-sitter-php, same parking format) recovered on this single bundle:
metadata.unresolved_calls(previously dropped silently)Suggested fix
$this->method()self-calls; interface calls -> all implementations.metadata.unresolved_calls(same payload format as other languages,"lang": "php") somerge-graphscan finish the edges.empty,count,strlen, ...) to an internal method — consult a builtin list per language before rewiring.Repro
Any PHP corpus containing
$this->someTypedProperty->method(): the edge is absent fromgraph.jsonand nothing appears inmetadata.unresolved_callsfor the caller. Then add a second method namedemptyanywhere in the corpus and observeempty()calls being wired to it.Happy to share our local post-processor (pure post-processing on
graph.json, idempotent) if useful as a reference implementation.