Skip to content

PHP: new Foo(...) produces no edge — object_creation_expression missing from _PHP_CONFIG.call_types #3115

Description

@BenWaNH

Summary

A class that a PHP method only instantiates gets no edge. new Foo(...) parses as
object_creation_expression, but _PHP_CONFIG.call_types does not list that node type,
so the construction site is never dispatched in walk_calls.

This is the same gap that #2997 reported for C#, fixed in #2998 by adding
object_creation_expression to the C# config. Java has had it since #1373. PHP never caught up.

Repro (graphify 0.9.50, tree_sitter_php 0.24.1)

Four files, graphify extract . --code-only:

// src/Foo.php, src/Bar.php, src/Baz.php  (namespace App)
class Foo { public function __construct(public int $x = 0) {} }
class Bar { public function __construct(public int $y = 0) {} }
class Baz { public static function create(): self { return new self(); } }
// src/Caller.php
class Caller
{
    public function run(Bus $bus): void
    {
        $a = new Foo(1);            // new in assignment
        $bus->dispatch(new Bar(2)); // new as argument
        $c = Baz::create();         // static call
    }
}
position edge emitted
new Foo(1) in assignment none
new Bar(2) as argument none
Baz::create() run --calls--> Baz

Only the static call produces an edge. Neither new site produces calls, references,
or any other relation — the classes exist as nodes, they are simply unreachable from the
constructing method.

Root cause

graphify/extract.py, _PHP_CONFIG:

call_types=frozenset({"function_call_expression", "member_call_expression",
                      "scoped_call_expression", "class_constant_access_expression"}),

object_creation_expression is absent. Confirmed against the grammar:

object_creation_expression -> new Foo(1)
object_creation_expression -> new Bar(2)

Impact on a real codebase

Symfony/DDD application, 615 PHP files, 4324 nodes / 10957 edges:
505 new X( sites across 178 distinct classes emit no edge.

The practical effect is worst on message-bus code, where construction is the control flow.
Of 22 $bus->dispatch(new SomeCommand(...)) sites, 0/22 have a calls/references edge
to the command they construct. Asking the graph "what happens when
AttachRecordToMessageEmailCommand is dispatched" returns the handler's neighbourhood
(repositories, value objects, unrelated domain events) but never the one command it chains to
— and there is no signal that the edge set is incomplete.

Related

#1682 covers instance/member call resolution in PHP ($this->prop->method()), which has a
different root cause (member calls are deliberately dropped to avoid false positives). This
report is only about the construction site itself, where the callee type is written literally
at the call site and needs no inference.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions