Variable declaration, naming rules, and scope
Concept
Variables in PHP are dynamically typed, prefixed with $, and do not require declaration before use. This flexibility comes with pitfalls that strict-types and modern PHP practices help mitigate.
Variable naming rules
- Must start with a letter or underscore, never a digit:
$name,$_private,$camelCase - Case-sensitive:
$userand$Userare different variables - PHP convention (PSR-12):
$camelCasefor local variables,$snake_caseis acceptable but less common in modern code - No type annotation on the variable itself (type annotations are on function parameters and class properties)
Variable scope
PHP's scope model is distinct from most languages and is a common interview topic:
Local scope: Variables inside a function are isolated. Unlike JavaScript, they do not have access to the enclosing scope or global variables unless explicitly requested.
Global scope: Variables declared at the top level of a script. Accessible inside functions only with the global keyword or via $GLOBALS superglobal.
global keyword: Brings a global variable into function scope. Modifying it inside the function modifies the global. Using global is discouraged in modern PHP — pass values as parameters instead.
Superglobals: Special variables available in all scopes without global: $_GET, $_POST, $_SERVER, $_SESSION, $_COOKIE, $_ENV, $_FILES, $_REQUEST, $GLOBALS.
Static variables: Declared with static inside a function. Persist between function calls within the same request but are reset between requests. Used for simple caching within a function (a pattern called "function-level memoization").
Variable lifecycle
PHP uses a copy-on-write (COW) mechanism. When you assign $b = $a, both variables point to the same memory. Only when you modify one does PHP create a separate copy. This makes assignments cheap for large strings and arrays.
isset() vs empty() vs is_null()
Three common checks with subtle differences:
isset($var):trueif variable exists AND is not null. Does not trigger a warning on undefined variables.empty($var):trueif variable is falsy (0, "", "0", null, [], false) OR undefined. Likeisset(), no warning on undefined.is_null($var):trueonly if value is exactlynull. TriggersE_WARNINGif variable is undefined.
Code Example
<?php
declare(strict_types=1);
// Variable declaration and scope
$globalCounter = 0;
function incrementCounter(): void
{
global $globalCounter; // Avoid this pattern in real code — pass as reference or use a class
$globalCounter++;
}
// Better: use static for simple within-request caching
function getExpensiveValue(): string
{
static $cached = null;
if ($cached === null) {
// Simulate expensive computation
$cached = strtoupper("computed value");
}
return $cached;
}
echo getExpensiveValue(); // "COMPUTED VALUE" (computed)
echo getExpensiveValue(); // "COMPUTED VALUE" (from static cache)
// Scope isolation — PHP function scope does NOT see outer variables
$message = "Hello from outer scope";
function showMessage(): void
{
// echo $message; // This would produce: Warning: Undefined variable $message
// Unlike JavaScript, PHP functions don't close over the parent scope
}
// Closures DO close over variables — but you must be explicit
$greet = function(string $name) use ($message): string {
return "{$message}, {$name}!";
};
echo $greet("Alice"); // "Hello from outer scope, Alice!"
// isset vs empty vs is_null
$zero = 0;
$empty = "";
$nullVal = null;
var_dump(isset($zero)); // true (0 is set, even if falsy)
var_dump(empty($zero)); // true (0 is empty)
var_dump(is_null($zero)); // false (0 is not null)
var_dump(isset($nullVal)); // false (null is treated as not set)
var_dump(empty($nullVal)); // true
var_dump(is_null($nullVal));// true
// Variable variables — rarely useful, almost always a code smell
$fieldName = 'email';
$$fieldName = 'user@example.com';
echo $email; // "user@example.com" — dynamic variable name
// Modern PHP: use arrays or objects instead of variable variables
$fields = ['email' => 'user@example.com', 'name' => 'Alice'];
echo $fields[$fieldName]; // Cleaner, explicit, analyzable by static toolsInterview Q&A
Q: Why can't a PHP function see variables from its enclosing scope without global or use?
PHP's scope model is intentionally isolated — each function has its own scope that does not automatically inherit variables from the calling context or global scope. This is different from JavaScript (where closures capture the lexical scope) and Python (which has the LEGB rule). The design prevents accidental variable name collisions in long functions and makes it clear exactly what data a function depends on. If you need data in a function, you must either pass it as a parameter (best practice), use global (global state — avoid), or for closures use use ($var) to explicitly capture from the enclosing scope. This explicit capture requirement forces you to declare your function's dependencies, which improves readability and testability.
Q: What is the difference between isset() and !empty() and when should each be used?
isset($var) returns true if the variable is defined AND not null. It returns false for undefined variables and null values, but returns true for 0, false, "", and []. empty($var) returns true if the variable is undefined OR has a falsy value (null, false, 0, "", "0", [], unset). Use isset() when you want to know "was this value explicitly provided, even if it's zero or false?" — typical for checking form fields or array keys. Use empty() when you want "is this field blank or missing?" — common for validation. The gotcha: empty("0") returns true, which surprises developers who expect "0" (a non-empty string) to not be empty. Always use isset() for existence checks; use !== null or explicit falsy checks for value checks.
Q: What is a static variable in a PHP function and how does it differ from a class static property?
A static variable declared inside a function retains its value between calls to that function within the same request, but is reset at the start of every new request (it's not persistent storage). It's function-scoped, not class-scoped. A class static property (static $count) is shared across all instances of a class and also resets between requests (unless cached externally). The function-level static is useful for simple memoization within a request — "compute this expensive value once per request, return cached on subsequent calls." The key limitation: static variables inside functions make testing harder because the cached state persists between test calls. Modern code uses injected caching (Redis, array cache) instead of function-level statics for anything that needs to be testable.