php-propiedades-y-metodos-static-en-php

Static Properties and Methods in PHP

  • 4 min

A static member is a property or method that belongs to the class and not to a specific instance.

Until now, we have said that the Class is the blueprint and the Object is the house. If Juan paints his house blue, Maria’s house does not change color. They are independent.

But what if we want to define a rule that applies to all houses in the subdivision? For example: “The garbage collection time is at 8:00 PM.” That does not depend on a specific house; it is a global rule of the community (the Class).

In PHP, this is called Static Members.

Static Properties and Methods (static)

A static member belongs to the Class, not the Object.

  • You don’t need to use new to use it.
  • It is shared among all instances. If one changes it, it changes for everyone.

The Scope Resolution Operator (::)

To access static members, we don’t use the arrow ->. We use the double colon :: (curiously known in Hebrew as Paamayim Nekudotayim).

class Calculadora {
    // Static Property: Belongs to the Calculadora class
    public static float $pi = 3.14159;

    // Static Method: Doesn't need an object to work
    public static function sumar(int $a, int $b): int {
        return $a + $b;
    }
}

// DIRECT USAGE (Without new)
echo Calculadora::$pi; // 3.14159
echo Calculadora::sumar(5, 10); // 15
Copied!

This is very useful for Utility Classes (Helpers) where it doesn’t make sense to create an object because we don’t store state, we just want to execute a function.

self:: vs $this

Here is the trap where everyone falls.

  • Inside a normal method, you use $this to refer to the current object.
  • Inside a static method, $this does not exist (because there is no object).

To refer to the class itself from within, we use self::.

class Contador {
    public static int $cuenta = 0;

    public function __construct() {
        // Every time we create an object, we increase the global counter
        self::$cuenta++;
    }

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

new Contador();
new Contador();
new Contador();

echo Contador::verTotal(); // Output: 3
Copied!
  • If it’s an instance variable ($var) -> $this->var
  • If it’s static (static $var) -> self::$var

Class Constants (const)

Unlike static properties (which can change: self::$cuenta++), constants are immutable. They are universal fixed values for that class.

By default, they are always public and static.

class Banco {
    public const IMPUESTO = 0.21;
    private const CLAVE_SECRETA = '1234'; // As of PHP 7.1 they can have visibility

    public function calcularTotal(float $monto): float {
        // We access them the same way as a static
        return $monto * (1 + self::IMPUESTO);
    }
}

echo Banco::IMPUESTO; // 0.21
Copied!

Technical Depth: self:: vs static:: (Late Static Binding)

This mechanism is called late static binding and has existed since PHP 5.3. Imagine you have inheritance:

class A {
    public static function quienSoy() {
        echo __CLASS__;
    }
    public static function test() {
        self::quienSoy(); // self is "bound" to the class where it is written (A)
    }
}

class B extends A {
    public static function quienSoy() {
        echo __CLASS__; // Should say B
    }
}

B::test(); // Output: "A" (Surprise!)
Copied!

Why does it print A? Because self:: refers to the class where the code was written (A), not to the one that calls it (B).

To solve this and allow polymorphism with statics, we use static::.

// In class A, we change self to static
public static function test() {
    static::quienSoy(); // static looks for the class that called it at runtime
}

B::test(); // Output: "B" (Correct!)
Copied!

Use static:: when you want an inherited class to be able to specialize behavior. Use self:: when the reference should remain bound to the class where it is written.

The Warning: Don’t Overuse Static

Static methods are convenient, but a mutable static property introduces shared state. A pure static method, on the other hand, doesn’t necessarily have to maintain global state.

They make code difficult to test (Unit Testing) because they create strong hidden dependencies (Coupling).

  • Good: Pure functions (Math, String converters).
  • Bad: Database::connect(). If you make that static, you won’t be able to easily change the database in your tests.