Variables, Constants, Scope, and References in PHP

Declare, assign, and reassign PHP variables correctly, understand variable scope and superglobals, and use constants, references, variable variables, and static local variables appropriately.

Variables are how a PHP script stores and manipulates data as it runs — every meaningful program is, at its core, a sequence of variable creations, reads, and updates. PHP's variable system has a few distinctive rules (the $ sigil, dynamic typing, function-level scope by default) that differ from many other languages, and getting comfortable with them — along with constants, scope, and the less common but occasionally essential features like references and variable variables — is foundational to everything that follows.

Naming and Assignment

Every PHP variable name starts with a dollar sign $, followed by a letter or underscore, then any combination of letters, numbers, and underscores — $user_name, $_total, and $item2 are all valid; $2item is not, because it starts with a digit. Variable names are case-sensitive, so $Name and $name are two entirely different variables — a frequent source of subtle bugs for beginners.

Assignment uses the = operator: $price = 19.99; creates the variable $price and stores the float value 19.99 in it. PHP is dynamically typed, meaning a variable's type is determined by whatever value it currently holds, not declared up front — the same variable can hold an integer at one point and a string later, though doing so intentionally is usually a code smell rather than a feature to lean on.

Reassignment simply uses = again: $price = 24.99; replaces the previous value. PHP assignment is by value for scalars and arrays by default — assigning $b = $a; copies $a's value into $b, so later changing $a does not affect $b. Objects are the exception: variables holding objects store a handle to the object, so assigning $b = $a; for objects makes both variables refer to the same underlying object instance.

• Variable names: start with $, then letter/underscore, then letters/digits/underscores. • Case-sensitive: $Name and $name are different variables. • Assignment/reassignment both use =. • Scalars and arrays are copied by value on assignment; objects are copied by handle (reference-like behavior).

Scope: Local, Global, and Superglobals

By default, every variable in PHP has function scope: a variable created inside a function only exists inside that function, and a variable created at the top level of a script ("global scope") is not automatically visible inside functions. This is different from many scripting languages where inner blocks can freely see outer variables. To use a global variable inside a function, you must explicitly declare it with the global keyword, or access it through the $GLOBALS superglobal array.

Superglobals are a special set of built-in arrays that are automatically available in every scope, without needing global — no import or declaration required. The most commonly used are $_GET (query-string parameters), $_POST (form-submitted data), $_SESSION (data persisted across requests for one visitor), $_COOKIE (cookies sent by the browser), $_SERVER (server and request metadata like $_SERVER['REQUEST_METHOD']), $_FILES (uploaded files), $_ENV (environment variables), and $_REQUEST (a merge of GET/POST/COOKIE, generally best avoided for clarity).

Unlike ordinary local variables, superglobals bypass scope rules entirely by design — they represent request-level or session-level state that legitimately needs to be reachable from anywhere, such as deep inside a function handling form validation.

• Function scope is the default: variables inside a function are invisible outside it, and vice versa. • global $x; inside a function pulls in the outer $x by reference to the global scope. • $GLOBALS['x'] accesses global scope from anywhere without the global keyword. • Superglobals ($_GET, $_POST, $_SESSION, $_COOKIE, $_SERVER, $_FILES, $_ENV, $_REQUEST) are available in every scope automatically.

Constants: const and define()

A constant holds a value that cannot change once set, and — unlike a variable — never uses the $ sigil when referenced. There are two ways to create one. define('MAX_USERS', 100); is a function call that works anywhere, including conditionally inside an if block, and the name is passed as a string. const MAX_USERS = 100; is a language construct evaluated at compile time, must be used at the top level of a file or inside a class (never conditionally or inside a function body), and its value must be a constant expression (no function calls or variables on the right-hand side in older PHP versions, though PHP 8.1+ relaxed some of these limits with enum and new-in-initializer support).

In practice, const is preferred at the top of a script or inside a class definition (class Config { const VERSION = '1.0'; }, or the modern public const VERSION = '1.0'; with visibility), because it's slightly faster (resolved at compile time) and reads more clearly as 'this never changes'. define() remains useful when a constant's existence needs to be conditional, e.g. only defining a default if it isn't already set by a config file.

Built-in "magic constants" like __LINE__, __FILE__, __DIR__, __FUNCTION__, and __CLASS__ are resolved by the parser based on where they appear in the code, and are extremely useful for logging and debugging.

• define('NAME', value); — runtime function call, usable conditionally, no $ sigil when read. • const NAME = value; — compile-time, top-level or inside a class only, no $ sigil. • Constants cannot be changed after being set. • Magic constants: __LINE__, __FILE__, __DIR__, __FUNCTION__, __CLASS__ resolve based on source position.

References, Variable Variables, and Static Local Variables

A reference lets two variable names point to the same underlying value, so that changing one changes the other. References are created with &: $b = &$a; makes $b an alias for $a — from that point on, they are indistinguishable, and unsetting one does not affect the other's value (only the alias). References are most commonly seen when passing a function parameter 'by reference' (function addOne(&$n) { $n++; }) so the function can modify the caller's variable directly, or when iterating an array with foreach and modifying elements in place (foreach ($arr as &$item) { $item *= 2; } — note this requires unset($item); afterward to avoid a subtle bug where the last reference lingers).

Variable variables let you use the value of one variable as the name of another, using a double dollar sign: $name = 'age'; $$name = 30; effectively creates a variable called $age with the value 30. This is a rarely-needed, somewhat exotic feature — most real use cases (like dynamic keys) are better served by arrays — but it appears occasionally in older codebases and dynamic templating code, so recognizing the syntax matters.

A static local variable is a function-scoped variable that retains its value between separate calls to that function, unlike ordinary local variables which are reset every call. Declared with static $count = 0; inside a function body, it is initialized only once (the first time the function runs) and then keeps its updated value across every subsequent call — useful for simple call counters, memoization, or lazily-initialized values inside a function without resorting to a global or a class property.

• Reference: $b = &$a; — two names for the same value; changing one changes the other. • Pass-by-reference parameter: function f(&$x) { ... } lets a function mutate the caller's variable. • Variable variable: $$name — uses the value of $name as another variable's name. • static $x = 0; inside a function — persists its value across calls, initialized only once.

Declaring Variables, Constants, and Scope Access

TAX_RATE and APP_NAME are read without a $ sigil. global $extraFee; is required for the function to see the outer $extraFee.

<?php
declare(strict_types=1);

$price = 19.99;         // local variable
const TAX_RATE = 0.08;  // compile-time constant
define('APP_NAME', 'SampleApp');

function total(float $price): float {
    global $extraFee;   // pull in a global variable explicitly
    return $price + ($price * TAX_RATE) + $extraFee;
}

$extraFee = 2.50;
echo total($price);

Code Examples

This demonstrates PHP's default function-scoping: the inner function has no access to $counter until it is explicitly pulled in with global. Expected result: undefinedundefined (second call prints) 10

Because $count is declared static, PHP initializes it to 0 only on the very first call and preserves its value across every later call to callCount(). Expected result: 123

Plain assignment copies the value, so mutating $b never touches $a; reference assignment makes $d and $c the same storage location, so mutating either one mutates both. Expected result: 510

Common mistake: Forgetting that foreach (... as &$item) leaves $item as a lingering reference after the loop — always unset($item) right after such a loop.

<?php
$counter = 10;

function showCounter() {
    echo $counter ?? 'undefined'; // cannot see the outer $counter
}

function showCounterGlobal() {
    global $counter;
    echo $counter;
}

showCounter();       // prints "undefined"
showCounterGlobal();  // prints "10"
<?php
function callCount(): int {
    static $count = 0;
    $count++;
    return $count;
}

echo callCount(); // 1
echo callCount(); // 2
echo callCount(); // 3
<?php
$a = 5;
$b = $a;      // copy
$b = 10;
echo $a;      // still 5

$c = 5;
$d = &$c;     // reference (alias)
$d = 10;
echo $c;      // now 10, because $d IS $c

Scope Boundaries

Ordinary variables respect function boundaries; superglobals ignore them by design.

Global scope
  ┌───────────────────────────────────┐
  │ $counter = 10;                     │
  │                                     │
  │  function f() {                    │
  │    ┌───────────────────────────┐  │
  │    │ local scope (fresh each     │  │
  │    │ call, no auto access to     │  │
  │    │ outer $counter)             │  │
  │    └───────────────────────────┘  │
  │  }                                  │
  └───────────────────────────────────┘
     $_GET / $_POST / $_SERVER / ... reach into EVERY scope

Important Rules

Use const for values known at compile time (top-level or class); use define() only when definition must be conditional.

Avoid relying on global in large codebases — pass values as parameters or use dependency injection instead.

Use $_REQUEST sparingly, if at all — prefer explicit $_GET/$_POST so data source is unambiguous.

Always unset($item) after a foreach (... as &$item) loop to avoid stale-reference bugs.

Reserve variable variables ($$name) for rare, well-justified cases — an associative array is almost always clearer.

Superglobals in a Real Request

A login handler typically reads submitted credentials from $_POST['username'] and $_POST['password'], validates them, and on success writes the authenticated user's ID into $_SESSION['user_id'] — all without ever needing global, because superglobals are reachable from any function or file in the request.

foreach ($items as &$item) { $item *= 2; } foreach ($items as $item) { echo $item; } foreach ($items as &$item) { $item *= 2; } unset($item); foreach ($items as $item) { echo $item; }

Without unset($item), the second foreach reuses the same $item variable name, which is still a reference to the last array element from the first loop — silently corrupting data on the last iteration.

function total() { return $price * 1.08; } // $price undefined here function total(float $price) { return $price * 1.08; }

A variable from the calling scope is not visible inside a function unless passed as a parameter or pulled in with global; relying on an outer $price silently fails or warns.

By default, can a function see a variable declared at the top level of the script? A. Yes, all variables are globally visible in PHP B. No, unless it is explicitly imported with global or accessed via $GLOBALS C. Only if the variable name starts with an underscore D. Only inside class methods

B. No, unless it is explicitly imported with global or accessed via $GLOBALS — PHP functions have their own local scope by default; outer/global variables require an explicit global declaration or $GLOBALS access.

Which is true about const versus define()? A. const can be used conditionally inside an if block; define() cannot B. define() is a runtime function call usable conditionally; const is resolved at compile time and must be top-level or in a class C. They are functionally identical in every way D. const requires the $ sigil when read; define() does not

B. define() is a runtime function call usable conditionally; const is resolved at compile time and must be top-level or in a class — define() is an ordinary function call that can appear anywhere at runtime, including conditionally; const is a compile-time construct restricted to top-level script code or class bodies.

What makes a static local variable different from a normal local variable? A. It is visible from every function in the script B. It resets to its initial value on every function call C. It keeps its value between separate calls to the same function D. It must always be a constant

C. It keeps its value between separate calls to the same function — A static local variable is initialized only once and retains its updated value across subsequent calls to that same function, unlike ordinary local variables which are recreated fresh each call.

Write a function nextId() that uses a static local variable starting at 100, increments it by 1 on every call, and returns the new value. Call it three times and print each result.

<?php function nextId(): int { static $id = 100; $id++; return $id; } echo nextId() . PHP_EOL; // 101 echo nextId() . PHP_EOL; // 102 echo nextId() . PHP_EOL; // 103

Use static $id = 100; inside the function, increment before returning.