fix(php): emit a calls edge for object creation, new Foo(...) (#3115) - #3169
fix(php): emit a calls edge for object creation, new Foo(...) (#3115)#3169abhay-codes07 wants to merge 1 commit into
Conversation
…hify-Labs#3115) `object_creation_expression` was absent from _PHP_CONFIG.call_types, so a class a method merely constructs got no edge at all - the PHP twin of the gap Java closed in Graphify-Labs#1373 and C# in Graphify-Labs#2997. On the reporter's Symfony corpus 505 `new X(` sites across 178 classes were invisible, worst on message-bus code where construction IS the control flow: 0 of 22 `$bus->dispatch(new SomeCommand(...))` sites had any edge to the command. PHP keeps the constructed class in a bare name/qualified_name child (no field), so the generic call path never names it; a dedicated engine branch (beside C#'s) reads it, naming the last segment of a qualified `new \App\Bar()` to match how the namespace pass keys classes. `new $cls()` is dynamic and `new self()`/`static`/`parent` name no other class - all stay unnamed rather than minting junk edges.
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Treats PHP new Foo(...) as a call so a method that only constructs a class links to it, matching the existing Java and C# behaviour. The engine reads the class from the bare name/qualified_name child (qualified names resolve to the last segment), while new $cls(), new self(), new static(), and new parent() stay unnamed rather than minting phantom edges.
Worth a look
- PHP constructor calls via
new parent()are silently dropped —graphify/extractors/engine.py:5169· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1924 functions depend on the 425 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract()— 502 callers, 42 callees - new:
_rebuild_code()— 98 callers, 50 callees - new:
_extract_generic()— 18 callers, 24 callees - new:
extract_xaml()— 19 callers, 17 callees - new:
extract_js()— 85 callers, 3 callees - new:
dispatch_command()— 2 callers, 122 callees - new:
extract_objc()— 27 callers, 9 callees - new:
_get_extractor()— 26 callers, 6 callees - …and 32 more — each is listed as a finding
Verification — 1924 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 1767 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify \_extract\_generic.
The verifier did not have enough to check \_extract\_generic, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set
· 40 more finding(s) on lines outside this diff (see the check run).
Closes #3115.
The problem
object_creation_expressionwas absent from_PHP_CONFIG.call_types, so a class a PHP method merely constructs got no edge at all — the PHP twin of the gap Java closed in #1373 and C# in #2997/#2998. On the reporter's Symfony/DDD corpus (615 files), 505new X(sites across 178 distinct classes emitted nothing, worst on message-bus code where construction is the control flow: 0 of 22$bus->dispatch(new SomeCommand(...))sites had any edge to the command they construct.The change
object_creation_expressionjoins_PHP_CONFIG.call_types.name/qualified_namechild — no field — so the generic call path never saw it. A qualifiednew \App\Bar()names the last segment, matching how the PHP namespace pass keys classes.new $cls()is dynamic and stays unnamed;new self()/new static()/new parent()name no other class and are skipped rather than minting junk nodes or edges.Tests
tests/test_php_object_creation.py— 6 tests mirroring the C# suite:newin assignment,newin argument position (the$bus->dispatch(new Bar(2))shape), qualified construction naming the last segment, dynamic/self/static producing nothing, existing static-call edges unchanged, and a cross-file dispatcher reaching its command class throughuse+new. With the fix reverted, 4 of 6 fail.test_php_type_resolutionis unchanged; the full suite matches the freshv8(0.9.51) baseline.