PHP Static Properties

La Lakshmi Priya Updated 19 Oct 2026
6 min read ·Lesson 140 of 143

What Is a Static Property?

In simple terms: A normal property belongs to each object — every product has its own price. A static property belongs to the class and is shared by all objects of that class. There is exactly one copy, no matter how many objects exist (even zero). It is like a counter on a shop's door that counts every visitor, rather than a badge each visitor carries.

Technically: A property declared with the static keyword is stored once per class. It is accessed with ClassName::$property from outside, or self::$property / static::$property inside the class — note the $ after ::. Static properties keep their values for the duration of the request (or process), across all objects and method calls.

Instance PropertyStatic Property
Declared asprivate int $countprivate static int $count
StorageOne per objectOne per class
Access$this->count, $obj->countself::$count, ClassName::$count
Exists without objectsNoYes

Declaring and Using Static Properties

<?php
final class Visitor
{
    private static int $count = 0;

    public function __construct(public readonly string $name)
    {
        self::$count++;
    }

    public static function count(): int
    {
        return self::$count;
    }
}

echo Visitor::count() . "\n";

$a = new Visitor('Asha');
$b = new Visitor('Bala');
$c = new Visitor('Charu');

echo Visitor::count() . "\n";

Output

0
3

How It Works

  1. private static int $count = 0; creates a single counter for the whole class.
  2. Every constructor call increments the same counter through self::$count.
  3. Visitor::count() can be called before any object exists; the property is available as soon as the class is loaded.
  4. The property is private, so only the class can change it; a static method exposes the value.

Syntax Reminder

self::$count        // static property: $ after ::
self::MAX_ITEMS     // constant: no $
self::create()      // static method
$this->name         // instance property: no $ after ->

Static Properties and Inheritance

A static property declared in a parent class is shared by the parent and all child classes — unless a child class redeclares it:

<?php
class Model
{
    protected static int $queries = 0;

    public static function recordQuery(): void
    {
        static::$queries++;
    }

    public static function queries(): int
    {
        return static::$queries;
    }
}

class User extends Model {}
class Product extends Model {}

class Order extends Model
{
    protected static int $queries = 0;   // redeclared: Order gets its own copy
}

User::recordQuery();
User::recordQuery();
Product::recordQuery();
Order::recordQuery();

echo "User: " . User::queries() . "\n";
echo "Product: " . Product::queries() . "\n";
echo "Model: " . Model::queries() . "\n";
echo "Order: " . Order::queries() . "\n";

Output

User: 3
Product: 3
Model: 3
Order: 1

What This Shows

  • User and Product do not redeclare $queries, so they share the property declared in Model: all three calls changed the same counter.
  • Order redeclares the property, so it has a separate counter.
  • static::$queries refers to the property of the class the method was called on (late static binding, see Late Static Binding); with self::$queries, Order::recordQuery() would have changed Model's counter instead.

Shared static state in a hierarchy is a common source of surprises. If each subclass needs its own value, redeclare the property or use an array keyed by static::class.


Practical Example: Caching Expensive Lookups

Static properties can cache results so that an expensive operation (a database query or API call) runs only once per request:

<?php
final class CurrencyRates
{
    private static array $cache = [];
    private static int $lookups = 0;

    public static function rate(string $currency): float
    {
        $currency = strtoupper($currency);

        if (!isset(self::$cache[$currency])) {
            self::$lookups++;
            self::$cache[$currency] = self::fetchRate($currency);
        }

        return self::$cache[$currency];
    }

    public static function lookups(): int
    {
        return self::$lookups;
    }

    private static function fetchRate(string $currency): float
    {
        // Simulates a slow API call
        return match ($currency) {
            'USD' => 83.2,
            'EUR' => 90.5,
            default => throw new InvalidArgumentException("Unknown currency: $currency"),
        };
    }
}

foreach (['USD', 'usd', 'EUR', 'USD'] as $currency) {
    echo "1 $currency = ₹" . CurrencyRates::rate($currency) . "\n";
}

echo "API lookups: " . CurrencyRates::lookups() . "\n";

Output

1 USD = ₹83.2
1 usd = ₹83.2
1 EUR = ₹90.5
1 USD = ₹83.2
API lookups: 2

Step-by-Step Explanation

  1. The first request for a currency calls fetchRate() and stores the result in the static $cache.
  2. Later requests for the same currency (including usd, normalized to USD) are answered from the cache.
  3. Four calls cause only two lookups.

This is called memoization. In real applications, a cache object (injected into the classes that need it, or a PSR-16 cache) is usually preferable, because it can be configured, shared across requests (Redis), and replaced in tests.


The Risks of Static State

Static properties behave like global variables scoped to a class. That brings the same risks:

RiskExample
Hidden couplingAny code anywhere can change the shared value (if it is public)
Test interferenceOne test fills a static cache; the next test sees stale data
Long-running processesIn queue workers or application servers (Swoole, RoadRunner, FrankenPHP worker mode), static values survive between requests and can leak one user's data into another user's request
Inheritance surprisesChild classes unintentionally share the parent's value

Guidelines

  • Keep static properties private and change them only through methods of the class.
  • Use them for data that is truly class-wide and safe to share: counters for debugging, caches of immutable data, registries filled at startup.
  • Provide a reset method for tests if necessary.
  • Never store per-user or per-request data in static properties when the code may run in a long-running process.

Rules and Details

RuleDetail
Typed static propertiesSupported, e.g. private static array $cache = [];
Default valuesConstant expressions only, like other properties
readonlyNot allowed for static properties
Access through an object$obj::$prop works; $obj->prop does not access the static property (it emits a notice and treats it as an undefined instance property)
Visibilitypublic, protected, private apply as usual

Common Mistakes

Forgetting the $ After ::

Effect: self::count refers to a constant named count, causing an "Undefined constant" error.

Fix: self::$count.

Using $this for Static Properties

Effect: $this->count refers to an instance property, not the static one.

Fix: Use self::$count or static::$count.

Using Static Properties as Global Variables

Effect: State changes from anywhere, hard-to-trace bugs.

Fix: Pass data explicitly or inject shared services.

Assuming Child Classes Have Their Own Copy

Effect: All subclasses share and overwrite one value.

Fix: Redeclare the property in each subclass, or key values by static::class.


Best Practices

  • Use static properties sparingly, for genuinely class-wide data.
  • Keep them private and encapsulated behind static methods.
  • Prefer injected objects (caches, registries, configuration) for shared state in applications.
  • Be careful with static state in long-running PHP processes.
  • Remember: self::$prop for properties, self::CONST for constants.

Official reference: https://www.php.net/manual/en/language.oop5.static.php

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 Home 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 Slicing Strings User-defined Functions Slicing Strings 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
Ask about this post
AI Ask about this post

Ask questions about PHP Static Properties and get answers drawn from it.

Signed-in readers only.