A static property or method belongs to the class itself, not to any individual instance of it — every object of that class shares the same static member, rather than each instance getting its own separate copy.
Static properties in PHP
class Counter
{
public static int $count = 0;
public function __construct()
{
self::$count++;
}
}
new Counter();
new Counter();
new Counter();
echo Counter::$count; // 3
$count is shared across every Counter instance — each new object increments the same single value, rather than each instance tracking its own independent counter.
Accessing static members: self:: vs. an instance
class Counter
{
public static int $count = 0;
}
Counter::$count; // correct — accessed via the class name
$counter = new Counter();
// $counter->count; // wrong syntax for a static property from outside the class
Static properties are accessed via the class name and :: (or self::/static:: from within the class), not via -> on an instance — using instance syntax on a static property is a common early PHP mistake.
Static methods in PHP
class MathHelper
{
public static function square(int $n): int
{
return $n * $n;
}
}
MathHelper::square(5); // 25 — no instance needed
A static method can be called without ever instantiating the class — this makes sense for a "helper" or "utility" function that doesn't need any per-instance state to do its job.
Static properties and methods in Java
public class Counter {
public static int count = 0;
public Counter() {
count++;
}
}
new Counter();
new Counter();
System.out.println(Counter.count); // 2
public class MathHelper {
public static int square(int n) {
return n * n;
}
}
MathHelper.square(5); // 25
Java's static syntax follows the identical concept, accessed via ClassName.member rather than PHP's ClassName::member — the difference is purely syntactic (. versus ::), not conceptual.
A static property inside a subclass
class Animal
{
public static int $population = 0;
}
class Dog extends Animal {}
class Cat extends Animal {}
Dog::$population++;
echo Cat::$population; // 1 — shared across ALL subclasses too, since it belongs to Animal
Unless a subclass redeclares its own static property with the same name, static members declared on a parent class are shared across every subclass as well, not just instances of the exact declaring class — a genuine gotcha if the intent was actually a separate counter per subclass.
When static is (and isn't) the right choice
Static suits genuinely stateless utility functions and values that are truly meant to be shared class-wide (a running total, a configuration constant, a factory method) — for anything that should vary per object instance, a regular (non-static) property or method is the correct choice, since static state is shared globally across the whole application's lifetime, which can introduce subtle bugs (and testing difficulties) if used where per-instance state was actually needed.