PHP: static call through an import alias resolves to the wrong same-named method
Version: 1.5.0 · Language: PHP (Laravel)
Summary
For a static call made through an import alias — Alias::method() where
use Some\Fqn\Klass as Alias; — the receiver is not used to disambiguate.
Resolution falls back to matching the method name alone, so when two classes
define the same method name the call is attributed to the wrong class,
silently.
extractPHPImports already captures the alias correctly, so this looks like the
mapping simply isn't consulted when resolving scoped_call_expression.
Reproduction
// app/Services/SettleService.php
namespace App\Services;
class SettleService {
public static function getSettlesToExcel($stores, $selected, $dayRange, $id) { /* … */ }
}
// app/Repositories/SettleRepository.php
namespace App\Repositories;
class SettleRepository {
public static function getSettlesToExcel($storeIds, $dayRange) { /* … */ }
}
// app/Http/Controllers/Backend/SettleController.php
namespace App\Http\Controllers\Backend;
use App\Services\SettleService as Settle; // ← alias
class SettleController extends Controller {
public function excel($stores, $startDay = null, $endDay = null, $id = null) {
return Settle::getSettlesToExcel($stores, request()->_SELECTED, [$startDay, $endDay], $id);
} // ↑ the SERVICE
}
Expected
SettleController::excel is a caller of App\Services\SettleService::getSettlesToExcel.
Actual
$ codegraph impact getSettlesToExcel
Impact: "App\Services::SettleService::getSettlesToExcel (app/Services/SettleService.php:46)" affects 1 symbols
app/Services/SettleService.php: getSettlesToExcel:46 ← no callers found
Impact: "App\Repositories::SettleRepository::getSettlesToExcel (app/Repositories/SettleRepository.php:105)" affects 3 symbols
app/Repositories/SettleRepository.php: getSettlesToExcel:105
app/Http/Controllers/Backend/SettleController.php: excel:52 ← WRONG CLASS
routes/web.php: GET /excel/{startDay?}/{endDay?}/{id?}:149
$ codegraph callers getSettlesToExcel --file app/Services/SettleService.php
No callers found for "getSettlesToExcel"
$ codegraph node excel --file app/Http/Controllers/Backend/SettleController.php
Calls → getSettlesToExcel (app/Repositories/SettleRepository.php:105) ← WRONG CLASS
What already works
extractPHPImports (src/resolution/import-resolver.ts) handles the alias:
const useRegex = /use\s+([\w\\]+)(?:\s+as\s+(\w+))?;/g;
// use App\Services\SettleService as Settle;
// → { localName: 'Settle',
// exportedName: 'SettleService',
// source: 'App\\Services\\SettleService' }
So the binding Settle → App\Services\SettleService is available. The gap seems
to be that a scoped_call_expression's receiver isn't resolved through that
mapping before name-matching the method.
(Separately, src/extraction/languages/php.ts's namespace_use_clause branch
reads only the qualified_name child and never the namespace_aliasing_clause,
so the import node it emits carries no alias either — may or may not be
relevant depending on which path feeds resolution.)
Why this matters for PHP/Laravel
use App\Services\XxxService as Xxx; is an extremely common Laravel convention,
and Service/Repository layers routinely share method names.
Measured on one real Laravel 5.7 project (281 files, 1,986 nodes, 2,626 edges):
- 27 method names defined in both the Service and the Repository layer —
create, update, delete, list, find, completed, received,
getSettles, updateSettle, addSettle, getQuantity, getSumData, …
- alias imports throughout the controllers (
Order ×7, Store/Settle/Diet ×5 each)
Effectively every Controller→Service edge is attributed to the Repository.
The failure is quiet: explore's verbatim source is unaffected and looks right,
so only the graph edges (impact / callers / callees, and explore's Flow
section when it picks the wrong same-named node) are wrong — with no warning that
the layer attribution is a guess.
Suggested direction
When resolving Receiver::method() (and $obj->method() where the receiver type
is known), resolve Receiver through the file's ImportMapping.localName first
and constrain the method lookup to that class; fall back to name matching only if
the receiver can't be resolved. Emitting multiple candidates (as the docs describe
for ambiguous calls) would already be better than silently choosing one.
Environment
- codegraph 1.5.0, macOS 26.5.2 (arm64)
- PHP 8 syntax, Laravel 5.7, 281 files indexed
PHP: static call through an import alias resolves to the wrong same-named method
Version: 1.5.0 · Language: PHP (Laravel)
Summary
For a static call made through an import alias —
Alias::method()whereuse Some\Fqn\Klass as Alias;— the receiver is not used to disambiguate.Resolution falls back to matching the method name alone, so when two classes
define the same method name the call is attributed to the wrong class,
silently.
extractPHPImportsalready captures the alias correctly, so this looks like themapping simply isn't consulted when resolving
scoped_call_expression.Reproduction
Expected
SettleController::excelis a caller ofApp\Services\SettleService::getSettlesToExcel.Actual
What already works
extractPHPImports(src/resolution/import-resolver.ts) handles the alias:So the binding
Settle → App\Services\SettleServiceis available. The gap seemsto be that a
scoped_call_expression's receiver isn't resolved through thatmapping before name-matching the method.
(Separately,
src/extraction/languages/php.ts'snamespace_use_clausebranchreads only the
qualified_namechild and never thenamespace_aliasing_clause,so the import node it emits carries no alias either — may or may not be
relevant depending on which path feeds resolution.)
Why this matters for PHP/Laravel
use App\Services\XxxService as Xxx;is an extremely common Laravel convention,and Service/Repository layers routinely share method names.
Measured on one real Laravel 5.7 project (281 files, 1,986 nodes, 2,626 edges):
create,update,delete,list,find,completed,received,getSettles,updateSettle,addSettle,getQuantity,getSumData, …Order×7,Store/Settle/Diet×5 each)Effectively every Controller→Service edge is attributed to the Repository.
The failure is quiet:
explore's verbatim source is unaffected and looks right,so only the graph edges (
impact/callers/callees, andexplore's Flowsection when it picks the wrong same-named node) are wrong — with no warning that
the layer attribution is a guess.
Suggested direction
When resolving
Receiver::method()(and$obj->method()where the receiver typeis known), resolve
Receiverthrough the file'sImportMapping.localNamefirstand constrain the method lookup to that class; fall back to name matching only if
the receiver can't be resolved. Emitting multiple candidates (as the docs describe
for ambiguous calls) would already be better than silently choosing one.
Environment