Static Variables

La Lakshmi Priya Updated 30 Oct 2026
11 min read ·Lesson 201 of 209

What Is a Static Variable?

In simple terms: A static variable is a variable inside a function that remembers its value between calls to that function.

Technically: A static variable is declared inside a function with the static keyword. It has local scope — it can only be used inside that function — but its lifetime extends across all calls to the function for the rest of the script's execution. It is initialized only once, the first time the declaration is reached.

Why Static Variables Exist

Normal local variables are destroyed when a function returns, and each new call starts from scratch. Sometimes a function needs to keep information between calls:

  • Counting how many times it has been called
  • Caching a result that is expensive to compute
  • Creating something once (such as a database connection) and reusing it
  • Generating unique sequential IDs

A global variable could store this, but it would be visible to — and changeable by — the entire program. A static variable keeps the value private to the function while still preserving it between calls.


The Problem Static Variables Solve

Without static

<?php
function countCall()
{
    $count = 0;
    $count++;
    echo "Called $count time(s)\n";
}

countCall();
countCall();
countCall();

Output

Called 1 time(s)
Called 1 time(s)
Called 1 time(s)

Each call creates a new $count, sets it to 0, increments it to 1, and destroys it when the function returns.

With static

<?php
function countCall()
{
    static $count = 0;
    $count++;
    echo "Called $count time(s)\n";
}

countCall();
countCall();
countCall();

Output

Called 1 time(s)
Called 2 time(s)
Called 3 time(s)

How It Works

  1. On the first call, PHP reaches static $count = 0;, creates the static variable, and sets it to 0.
  2. $count++ makes it 1, which is printed.
  3. When the function returns, $count is not destroyed. PHP keeps its value attached to the function.
  4. On the second call, PHP sees that $count already exists, so the initializer = 0 is skipped. The previous value 1 is used, and $count++ makes it 2.
  5. The third call continues from 2 to 3.

The key detail: the initializer runs only once. That is what distinguishes static $count = 0; from $count = 0;.


Syntax

static $variableName = initialValue;
PartMeaning
staticKeyword that gives the variable a lifetime beyond a single call
$variableNameA normal variable name, local to the function
= initialValueOptional. Value used the first time only. Defaults to null if omitted.

Multiple static variables can be declared in one statement:

static $calls = 0, $lastArgument = null;

What the Initial Value Can Be

Before PHP 8.3, the initial value had to be a constant expression — a literal, a constant, or a simple calculation using them:

static $count = 0;              // literal
static $limit = 60 * 60;        // constant arithmetic
static $items = [];             // empty array
static $rate = TAX_RATE;        // constant

Function calls were not allowed:

static $startTime = microtime(true); // Fatal error before PHP 8.3

Since PHP 8.3, static variable initializers may contain arbitrary expressions, including function calls. The expression is still evaluated only once, on the first call.

If your code must support versions older than 8.3, initialize with null and assign on first use, as shown in the caching examples below. That pattern works on every PHP version.


Static vs Local vs Global

AspectLocal VariableStatic VariableGlobal Variable
DeclaredInside a functionInside a function with staticOutside functions
VisibleOnly inside the functionOnly inside the functionOnly outside functions (unless imported with global)
LifetimeOne function callEntire script executionEntire script execution
InitializedEvery callOnceWhen assigned
Can other code change it?NoNoYes — any code using global or $GLOBALS

Static variables combine the privacy of local variables with the persistence of global variables.


Lifetime: One Request, Not Forever

Static variables keep their values for the duration of the current script execution — in a web application, a single HTTP request. They are not shared between requests or between users.

Example

<?php
function pageViews()
{
    static $views = 0;
    $views++;
    return $views;
}

echo "Views: " . pageViews();

Output (every time the page is refreshed)

Views: 1

Why

PHP's shared-nothing architecture destroys all memory when a request ends, including static variables. The next request starts a fresh script. To count page views across requests, store the count in a database, a file, or a cache server.

Note: Long-running PHP runtimes (such as queue workers or application servers like RoadRunner, Swoole, or FrankenPHP worker mode) keep the same process alive across many jobs or requests. In those environments, static variables do persist between requests, which can leak data from one user to another if you are not careful. Avoid storing user-specific data in static variables.


Practical Use 1: Caching an Expensive Result

A common use of static variables is memoization — computing a value once and returning the stored result on later calls.

Example

<?php
function getSettings(): array
{
    static $settings = null;

    if ($settings === null) {
        echo "(Loading settings from storage...)\n";

        // In a real application: read a file, query a database, or call an API
        $settings = [
            'siteName' => 'GoLearn',
            'currency' => 'INR',
            'itemsPerPage' => 20,
        ];
    }

    return $settings;
}

echo getSettings()['siteName'] . "\n";
echo getSettings()['currency'] . "\n";
echo getSettings()['itemsPerPage'] . "\n";

Output

(Loading settings from storage...)
GoLearn
INR
20

Step-by-Step Explanation

  1. First call: $settings is initialized to null. The condition $settings === null is true, so the settings are loaded and stored in the static variable.
  2. Second and third calls: $settings already holds the array, so the loading block is skipped entirely and the stored array is returned immediately.
  3. The message "Loading settings..." appears only once, proving the expensive work happened once.

Why === null Instead of empty()

If the loaded value could legitimately be empty (for example, an empty array when no settings exist), empty($settings) would reload on every call. Checking strictly against the initial null distinguishes "not loaded yet" from "loaded, but empty".

This pattern is useful when many parts of a page request the same data. Without caching, each call would repeat the database query or file read.


Practical Use 2: Memoizing Recursive Calculations

Recursive functions often recalculate the same values many times. A static cache can eliminate this repeated work.

Example

<?php
function fibonacci(int $n): int
{
    static $cache = [];

    if ($n <= 1) {
        return $n;
    }

    if (isset($cache[$n])) {
        return $cache[$n];
    }

    $cache[$n] = fibonacci($n - 1) + fibonacci($n - 2);

    return $cache[$n];
}

echo fibonacci(10) . "\n";
echo fibonacci(50) . "\n";

Output

55
12586269025

How It Works

  • The Fibonacci sequence is 0, 1, 1, 2, 3, 5, 8, … where each number is the sum of the previous two.
  • Without caching, fibonacci(50) would make billions of recursive calls, because the same values are recomputed again and again.
  • With the static $cache array, each value from 2 to 50 is calculated once and stored. Later requests for the same $n return the stored value immediately.
  • All recursive calls share the same $cache, because they are calls to the same function.
  • The cache persists after the first call, so the second call, fibonacci(50), reuses the values already computed for fibonacci(10).

Recursion is covered in the Recursive Functions lesson.


Practical Use 3: Generating Unique IDs

Example

<?php
function nextFieldId(string $prefix = 'field'): string
{
    static $counter = 0;
    $counter++;

    return $prefix . '-' . $counter;
}

$nameId = nextFieldId();
$emailId = nextFieldId();
$phoneId = nextFieldId('input');
?>
<label for="<?= $nameId ?>">Name</label>
<input id="<?= $nameId ?>" name="name">

<label for="<?= $emailId ?>">Email</label>
<input id="<?= $emailId ?>" name="email">

<label for="<?= $phoneId ?>">Phone</label>
<input id="<?= $phoneId ?>" name="phone">

Output (HTML)

<label for="field-1">Name</label>
<input id="field-1" name="name">

<label for="field-2">Email</label>
<input id="field-2" name="email">

<label for="input-3">Phone</label>
<input id="input-3" name="phone">

Why This Is Useful

HTML id attributes must be unique on a page, and <label for="..."> must match the input's id for accessibility and for clicking a label to focus its input. When form fields are generated by functions or included components, a static counter guarantees unique IDs without passing a counter around manually.

Notice that the counter is shared across all calls regardless of the prefix argument, which is why the phone field gets 3, not 1.


Practical Use 4: Creating a Resource Once

Opening a database connection is relatively slow. A static variable can ensure that a page uses a single connection, no matter how many functions request it.

<?php
function db(): PDO
{
    static $pdo = null;

    if ($pdo === null) {
        $pdo = new PDO(
            'mysql:host=localhost;dbname=shop;charset=utf8mb4',
            'shop_user',
            'secret',
            [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
        );
    }

    return $pdo;
}

// Anywhere in the application:
// $products = db()->query('SELECT name FROM products')->fetchAll();

How It Works

  • The first call to db() creates the PDO connection and stores it.
  • Every later call returns the same connection object.
  • PDO is covered in the MySQL Database section; here, the focus is the "create once, reuse" pattern.

Note: In real projects, keep credentials in environment variables or configuration files outside the web root, not in source code. In larger applications, a dependency injection container usually manages shared resources like this, because it makes them easier to replace in tests.


Static Variables in Class Methods

Static variables can also be used inside methods of a class. Their behavior with inheritance changed in PHP 8.1.

Example

<?php
class Counter
{
    public function increment(): int
    {
        static $count = 0;
        return ++$count;
    }
}

class SpecialCounter extends Counter
{
}

$a = new Counter();
$b = new SpecialCounter();

echo $a->increment() . "\n";
echo $b->increment() . "\n";
echo $a->increment() . "\n";

Output (PHP 8.1 and newer)

1
2
3

Explanation

  • The static variable belongs to the method, not to an object. All objects calling the same method share one $count, so $a and $b increment the same counter.
  • Since PHP 8.1, an inherited method (one the child class does not override) shares its static variables with the parent's method. Before PHP 8.1, SpecialCounter had its own separate copy, and the output was 1, 1, 2.

When state belongs to a class, a static property (private static int $count = 0;) is usually clearer than a static variable inside a method, because it is visible in the class definition. Static properties are covered in PHP Static Properties.

Not the same thing: static is also used for static methods, static properties, static fn closures, and late static binding (static::). These are different features that share the keyword. This lesson covers only static variables inside functions.


Limitations

  • No access from outside. No other code can read or reset a function's static variable. If you need to clear a cache (for example, in tests), you must design the function with an explicit way to do so, such as a reset parameter.
  • Hidden state. A function with a static variable can return different results for the same arguments depending on earlier calls. This makes behavior harder to predict and to test.
  • Memory growth. A static cache that stores every result keeps growing for the whole request. For a large number of possible inputs, limit the cache size.
  • Per-request only in traditional PHP; cross-request in long-running workers.

Common Mistakes

Expecting a Value to Persist Across Page Loads

What happens: A counter or cache resets on every request.

Why: Static variables live for one script execution.

Fix: Use sessions for per-user data, and a database, file, or cache server for shared data.

Using a Function Call as the Initial Value on PHP Older Than 8.3

static $start = time();

What happens: Fatal error: Constant expression contains invalid operations on PHP 8.2 and older.

Fix: Upgrade to PHP 8.3+, or initialize with null and assign the value on first use.

Resetting the Value on Every Call

<?php
function countCall()
{
    static $count;
    $count = 0;   // runs on every call
    $count++;
    return $count;
}

What happens: The function always returns 1.

Why: $count = 0; is an ordinary assignment, not the static initializer, so it executes every time.

Fix: Put the initial value in the declaration: static $count = 0;.

Storing User-Specific Data in Long-Running Workers

What happens: Data from one request (such as the current user) appears in another request handled by the same worker process.

Fix: Do not keep request- or user-specific data in static variables; pass it explicitly.

Using Static Variables Where Parameters Belong

What happens: A function's result depends on previous calls in surprising ways, and tests become order-dependent.

Fix: Use static variables only for caching, counters, and one-time setup — not as a way to pass data between calls.


Best Practices

  • Use static variables for caching, counting, and one-time initialization inside a single function.
  • Initialize caches with null and check with === null to distinguish "not loaded" from "empty".
  • Keep cached values small, or limit the number of stored entries.
  • Prefer static properties when the state belongs to a class.
  • Avoid storing user- or request-specific data in static variables.
  • For shared resources in larger applications, consider dependency injection instead of hidden static state.

Official reference: https://www.php.net/manual/en/language.variables.scope.php#language.variables.scope.static

0 Comments

Reviewed before they appear

No comments yet.

PHP
PHP Home PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement PHP Intro PHP Install PHP Built-in Web Server PHP Syntax PHP Tags PHP and HTML PHP Comments PHP Multiline Comments PHP Variables Variables Scope PHP Casting Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence Continue Statement Modify Strings PHP If...Else...Elseif PHP If Modify Strings PHP If Operators PHP Functions Concatenate Strings PHP If...Else User-defined Functions Slicing Strings Function Arguments PHP Shorthand if Escape Characters Default Argument Values PHP Nested if Pass by Reference String Interpolation Named Arguments PHP File Upload Variadic Functions Return Values Search in Strings Multibyte Strings Type Declarations in Functions PHP Numbers PHP Math PHP Floats PHP Random Numbers PHP Constants PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Cookies PHP Destructor PHP Access Modifiers Readonly Properties PHP Sessions PHP Inheritance Method Overriding PHP Filters The final Keyword CSRF Protection PHP Filters Advanced Session Security Secure Cookies PHP Magic Constants File Upload Security PHP Callback Functions PHP Operators Filesystem Security PHP JSON Arithmetic Operators Error Reporting in Production Hiding PHP Assignment Operators PHP Configuration (php.ini) Comparison Operators PHP Command Line (CLI) PHP Exceptions Increment / Decrement Operators Migrating to PHP 8 PHP Form Validation PHP Form Required PHP Form URL/E-mail Error Handling Form Input Sanitizing Escaping Output (htmlspecialchars) Custom Error Handler Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting Error Logging HTTP Headers and Redirects Output Buffering Sending Email PHP cURL Consuming REST APIs PHP Generators AJAX PHP AJAX Database AJAX XML AJAX Live Search AJAX Poll AJAX with JSON Security Introduction Password Hashing SQL Injection Prevention XSS Prevention Garbage Collection Project: Simple Blog PHP What is OOP PHP Classes/Objects The $this Keyword Access Array Items Update Array Items Add Array Items Remove Array Items Sorting Arrays Multidimensional Arrays Array Destructuring Array Spread Operator Search in Arrays Merge Arrays PHP Abstract Classes PHP Interfaces Polymorphism PHP Traits PHP Static Methods PHP Static Properties Late Static Binding Magic Methods Object Cloning MySQL Database MySQL Connect MySQL Create DB MySQL Create Table MySQL Insert Data MySQL Get Last ID MySQL Insert Multiple MySQL Prepared MySQL Select Data MySQL Where Debugging PHP Project: Image Upload Gallery $_SESSION $_ENV PHP RegEx RegEx Patterns Heredoc and Nowdoc RegEx Modifiers preg_match preg_replace preg_split PHP RegEx Functions Nullable Types Mixed and Never Types Nullsafe Operator PHP Attributes PHP Fibers Readonly Classes Property Hooks (PHP 8.4) Asymmetric Visibility (PHP 8.4) Reflection API SPL Data Structures Composer PHP Form Handling PHP XML Parsers PDO Transactions PDO Error Handling PHP XML Parsers PHP SimpleXML Parser PHP SimpleXML - Get PHP XML Expat Parser PHP DOM Parser PHP XMLReader PHP XMLWriter AJAX Intro PHP Class Constants Encryption with Sodium Recursive Functions Variable Functions Anonymous Functions Closures Arrow Functions First-class Callable Syntax PHP Arrays Indexed Arrays Associative Arrays Create Arrays Variables Scope Static Variables Variable Variables PHP Echo / Print PHP printf / sprintf PHP Data Types PHP Booleans PHP NULL PHP Strings String Functions
Ask about this post
AI Ask about this post

Ask questions about Static Variables and get answers drawn from it.

Signed-in readers only.