# Framework-Aware PHP Parsing Capabilities in code-review-graph: A Deep Dive into Laravel-Aware Static Analysis

> Explore framework-aware PHP parsing in code-review-graph. Discover how it leverages Composer PSR-4, Blade, and Laravel semantics for advanced static analysis and edge creation.

- Repository: [Tirth Kanani/code-review-graph](https://github.com/tirth8205/code-review-graph)
- Tags: deep-dive
- Published: 2026-08-18

---

**`code-review-graph` provides framework-aware PHP parsing that combines generic PHP construct analysis with Composer PSR-4 resolution, Blade template edge detection, and an evidence-gated Laravel post-pass that creates Route-to-controller and Eloquent relationship edges only when provable framework semantics exist.**

Static analysis tools for PHP often stop at syntax trees, but `code-review-graph` (from `tirth8205/code-review-graph`) treats PHP as a first-class citizen with deep framework integration. Its parser recognizes that modern PHP codebases rely on Composer autoloading, Laravel's routing and ORM conventions, and Blade templating—then weaves these into a unified graph representation.

## Core PHP Construct Analysis

The parser indexes fundamental PHP language features as distinct graph nodes. In [`code_review_graph/parser.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/parser.py), the `_resolve_php_scoped_calls` method handles trait usage, enum definitions, object-creation expressions with `new`, and base-class extension clauses.

This ensures every type reference creates traceable edges in the code graph, not just anonymous syntax nodes.

## Composer PSR-4 Resolution

Class-to-file mapping follows Composer's longest-prefix rule with multi-directory support and result caching.

The `CodeParser._resolve_module_to_file` method takes a fully-qualified class name and resolves it against the repository's [`composer.json`](https://github.com/tirth8205/code-review-graph/blob/main/composer.json) PSR-4 mappings. Search is bounded to the repository root to prevent external leakage.

```python
from pathlib import Path
from code_review_graph.parser import CodeParser

# Composer PSR-4 resolution in action

parser = CodeParser(repo_root=Path("/my/repo"))
qualified = parser._resolve_module_to_file(
    "App\\Service\\Mailer",               # Fully-qualified class name

    "/my/repo/src/Mailer.php",           # Current file (used for relative look-ups)

    "php"
)

# qualified → "/my/repo/src/Service/Mailer.php"

```

Multi-directory mappings are supported, and results are cached to avoid repeated filesystem traversal. The resolution logic lives within [`parser.py`](https://github.com/tirth8205/code-review-graph/blob/main/parser.py) and is invoked from the scoped-call resolver at line 11050 and surrounding context.

## Blade Template Reference Detection

The parser recognizes Laravel's Blade templating through extension-based language detection. When processing [`.blade.php`](https://github.com/tirth8205/code-review-graph/blob/main/.blade.php) files, it identifies `@include`, `@extends`, and similar directives while deliberately ignoring commented or escaped variants.

These create directed edges from the template file to its referenced views, enabling end-to-end flow analysis from PHP controllers through to view layers.

```python
from pathlib import Path
from code_review_graph.parser import CodeParser

# Blade template reference detection

blade_path = Path("resources/views/welcome.blade.php")
nodes, edges = CodeParser().parse_file(blade_path)

# An edge is created from the Blade file to any included view (@include('partials.foo'))

```

The blade-specific logic is gated by `detect_language` handling of the "blade" extension, ensuring this analysis only fires for appropriate file types.

## Laravel Semantic Post-Pass

After generic PHP analysis completes, a dedicated Laravel post-pass inspects nodes for explicit framework evidence. This is **evidence-gated analysis**: edges are created only when provable Laravel semantics exist.

The post-pass triggers on:

- `Route::` definitions (`Route::get()`, `Route::post()`, etc.)
- Eloquent model method calls (`hasMany()`, `belongsTo()`, etc.)
- Imported Laravel facades or known framework receivers

### Evidence Requirements

The `resolve_target` function (lines L11194-L11242 within `_resolve_php_scoped_calls`) requires at least one of:

- Fully-qualified class name
- Explicit `use` import statement
- `self` or `static` reference within the same class
- Matching namespace resolution

If none match, the call remains unresolved rather than guessed.

```python
from pathlib import Path
from code_review_graph.parser import CodeParser

# Parse a single PHP file and see the generic PHP nodes/edges

php_file = Path("src/Order/Queue/Mailer.php")
nodes, edges = CodeParser().parse_file(php_file)

# Resolve a Laravel route definition (evidence-gated)

store = CodeParser().parse_file(Path("routes/web.php"))[1]

# edges now contains Route→Controller edges if the route points to a real controller

```

### Edge Types Generated

When evidence is sufficient, the parser creates:

- **Route-to-controller edges**: `Route::get('/users', [UserController::class, 'index'])` becomes a directed edge from the route definition to the controller method
- **Eloquent relationship edges**: `User::hasMany(Post::class)` creates edges between model classes based on ORM semantics

The Laravel branch is clearly demarcated in [`parser.py`](https://github.com/tirth8205/code-review-graph/blob/main/parser.py) by the comment "PHP / Laravel semantic constructs" and subsequent resolution logic within `_resolve_php_scoped_calls`.

## File Organization and Implementation

| File | Purpose |
|------|---------|
| [`code_review_graph/parser.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/parser.py) | Central implementation; `_resolve_php_scoped_calls` contains both generic PHP and Laravel-specific logic |
| [`docs/FEATURES.md`](https://github.com/tirth8205/code-review-graph/blob/main/docs/FEATURES.md) | High-level capability documentation |
| [`docs/superpowers/specs/2026-07-17-php-laravel-parser-design.md`](https://github.com/tirth8205/code-review-graph/blob/main/docs/superpowers/specs/2026-07-17-php-laravel-parser-design.md) | Design specification for the Laravel post-pass and evidence-gated edge creation |
| [`tests/test_php_laravel.py`](https://github.com/tirth8205/code-review-graph/blob/main/tests/test_php_laravel.py) | Validation suite covering Composer resolution, Blade detection, and Laravel edge generation |

## Summary

- **Generic PHP constructs** (traits, enums, `new` expressions, base classes) are indexed as graph nodes via `_resolve_php_scoped_calls`
- **Composer PSR-4 resolution** maps class names to files using longest-prefix matching with caching, implemented in `_resolve_module_to_file`
- **Blade template edges** connect views to their includes through extension-gated analysis
- **Laravel semantic post-pass** creates Route-to-controller and Eloquent relationship edges only when explicit framework evidence exists
- **Evidence-gated resolution** prevents false positives by requiring qualified classes, imports, or self/static references

## Frequently Asked Questions

### How does code-review-graph handle PSR-4 autoloading with multiple source directories?

The `CodeParser._resolve_module_to_file` method supports multi-directory mappings defined in [`composer.json`](https://github.com/tirth8205/code-review-graph/blob/main/composer.json). It applies the longest-prefix matching rule to determine the correct file path, caches results for performance, and constrains searches to the repository root to maintain boundary safety.

### What prevents the Laravel parser from creating false-positive edges?

The parser implements evidence-gated analysis through the `resolve_target` function (lines L11194-L11242). It requires at least one of: fully-qualified class name, explicit `use` import, `self`/`static` reference, or matching namespace. Without this evidence, calls remain unresolved rather than guessed.

### Does Blade template analysis require a full Laravel installation?

No. Blade detection operates on file extension ([`.blade.php`](https://github.com/tirth8205/code-review-graph/blob/main/.blade.php)) and directive pattern matching within the generic PHP parser infrastructure. The `detect_language` function gates Blade-specific logic, and the analysis processes template files independently of runtime Laravel availability.

### Where is the Laravel-specific parsing logic located?

All PHP-related parsing, including the Laravel post-pass, resides in `CodeParser._resolve_php_scoped_calls` within [`code_review_graph/parser.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/parser.py). The Laravel branch follows a comment marker "PHP / Laravel semantic constructs" and implements framework-aware edge creation after generic PHP analysis completes.