← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

Symbol Table Resolution

compiler PHP 5.3+ Advanced
debt(d3/e3/b3/t7)
d3 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'default linter catches the common case' (d3), bordering specialist. Undefined variables and missing class imports surface as compile-time errors instantly for the most common cases, and the detection_hints tools phpstan and psalm catch closure capture and namespace resolution issues; a careful d3 fits the everyday case more than d5.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). quick_fix is mechanical: add missing use imports, list captured variables in use() clauses, or rename shadowed variables. These are small targeted edits within a single file/function, slightly more than a one-line swap when multiple identifiers need re-scoping.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). Scope and resolution decisions are mostly contained to the function or namespace where they occur; while applies_to spans web/cli/library, a single mis-scoped variable or import doesn't reshape the whole system — it taxes the component that contains it.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception that resolution is a one-time parser lookup, combined with PHP's function-scoping (no block scope), closures not auto-capturing outer variables, and namespace-relative class resolution, all contradict how a developer coming from block-scoped, auto-capturing languages would expect. The 'obvious' assumption is consistently wrong here.

About DEBT scoring →

Also Known As

name resolution name binding scope resolution identifier binding

TL;DR

The compiler phase that maps identifiers (variables, functions, classes) to their declarations, scopes, and types during semantic analysis.

Explanation

Namespaces add a separate resolution pass: unqualified class names resolve against `use` imports, then the current namespace, with no global fallback - which is why a missing `use` produces 'class not found' even when the class exists globally. Unqualified function and constant names, by contrast, do fall back to the global namespace.

Common Misconception

Symbol resolution is just a lookup that happens once the parser finishes. In reality it is a distinct semantic phase that tracks nested scopes and can fail with errors the parser never sees, like undefined variables or unresolved imports.

Why It Matters

Resolution errors are the most common compile-time failures developers hit - missing imports, typos in names, shadowed variables - and understanding scope rules prevents subtle bugs where a name silently binds to the wrong declaration.

Common Mistakes

  • Assuming variables have block scope in PHP - they are function-scoped, so a variable declared inside an if block leaks to the rest of the function.
  • Forgetting that closures do not capture outer variables automatically in PHP and must list them in a use() clause.
  • Omitting a use statement and expecting an unqualified class name to resolve globally - it resolves against the current namespace first.
  • Shadowing an outer variable with a same-named inner one and being surprised the outer value is unchanged.
  • Relying on case-insensitive function and class names while assuming variable names are also case-insensitive.

Avoid When

  • Do not manually reason about complex namespace resolution when a static analyser like PHPStan or Psalm can flag unresolved names automatically.
  • Avoid relying on global fallback resolution for classes - it never happens, so always import classes explicitly with use.

When To Use

  • Reach for explicit use() capture lists whenever a closure must read or mutate outer variables across PHP's function scope boundary.
  • Use namespace imports and fully qualified names deliberately when resolving classes so the compiler binds the intended declaration.

Code Examples

✗ Vulnerable
$count++; // $count is undefined here; warns, treats null as 0, returns 1 each call
✓ Fixed
<?php
namespace App;

use Monolog\Logger;

function makeCounter() {
    $count = 0;
    // Bind $count by reference so the closure shares the same symbol
    return function () use (&$count) {
        $count++;
        return $count;
    };
}
$next = makeCounter();
echo $next(); // 1
echo $next(); // 2 - resolution captured the outer binding

$logger = new Logger('app'); // resolves to Monolog\Logger

Added 6 Jun 2026
Views 8
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 2 pings S 3 pings S 0 pings M 2 pings T 1 ping W
Ahrefs 1
Scrapy 2
Google 4 Scrapy 3 Ahrefs 1
crawler 7 crawler_json 1
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Medium
⚡ Quick Fix
Track which scope each identifier lives in - add missing use imports for classes, list captured variables in closure use() clauses, and rename shadowed variables to avoid silent rebinding.
📦 Applies To
PHP 5.3+ web cli library
🔗 Prerequisites
🔍 Detection Hints
Closure accessing an outer variable without use(); new ClassName() in a namespace without a matching use import; variable assumed visible outside the block it was declared in
Auto-detectable: ✓ Yes phpstan psalm
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: Function Tests: Update

✓ schema.org compliant