devnotes.

Static Properties and Methods

Most properties and methods belong to a specific instance — car1.speed is different from car2.speed. A static (or 'class-level') member instead belongs to the class itself, shared by every instance, and accessible without creating any object at all.

class Car {
    static totalCarsCreated = 0 // shared across ALL Car instances
    speed = 0                    // unique to each instance

    function __construct() {
        Car.totalCarsCreated += 1 // increments the shared counter
    }

    static function getTotalCreated() {
        return Car.totalCarsCreated
    }
}

car1 = new Car()
car2 = new Car()
car3 = new Car()

print(Car.getTotalCreated()) // 3 — one shared value, not per-instance

Notice Car.totalCarsCreated is accessed on the class, not on any instance (Car.x, not car1.x), signaling it's shared, global state for that class rather than per-object data.

Common legitimate uses for static members:

  • Counters and registries tracking something across all instances (as above)
  • Constants — Math.PI, Color.RED — values that never change and don't need per-instance storage
  • Utility / helper methods that don't need any instance state — Math.max(a, b), StringUtils.capitalize(str)
  • Factory methods — static methods that construct and return new instances, often with more descriptive names than a raw constructor: User.createGuest()

A caution: overusing static state for things that should really be per-instance data is a common anti-pattern — it effectively recreates the same 'everything is global' problems OOP encapsulation is meant to solve, just at the class level instead of the whole-program level.

Static Properties and Methods in OOP | DevNotes