Un método o una propiedad static pertenece a la propia clase y no a ningún objeto. Llamas a un método estático con ClassName::method() y lees una propiedad estática con ClassName::$property, sin crear antes un objeto. Dentro de la clase, self:: se refiere a los mismos miembros.
No hay ningún new Temperature() por ninguna parte. Los miembros estáticos son útiles para funciones auxiliares que no necesitan el estado de un objeto (conversiones, factorías, validación) y para datos que pertenecen a la clase en conjunto, como un contador.
Las propiedades estáticas las comparten todos los objetos
Una propiedad normal tiene un valor por objeto. Una propiedad estática tiene un valor para toda la clase, así que todos los objetos ven el mismo. Aquí cada nuevo User incrementa un contador compartido y recibe el siguiente ID:
Fíjate en el $ de self::$nextId: las propiedades estáticas lo conservan después de ::, mientras que las constantes (self::MAX) no. Una propiedad estática vive solo durante una petición de PHP. En un sitio web típico (PHP-FPM o Apache) vuelve a empezar con cada carga de página, así que no es un lugar para guardar datos entre visitantes.
Los métodos estáticos no tienen $this
Un método estático se ejecuta sin objeto, así que $this no existe dentro de él. Un método estático puede llamar a otros métodos estáticos con self::, pero no puede leer propiedades normales. Llamar a un método normal de forma estática también falla:
La dirección contraria no da problemas: un método normal puede llamar a métodos estáticos, como hace withSeparator() con self::make().
self vs static: late static binding
self:: apunta a la clase donde está escrito el código. static:: apunta a la clase sobre la que se llamó el método en tiempo de ejecución. La diferencia solo aparece con herencia, y donde más importa es en los métodos factoría:
Post::createWithSelf() devuelve un Model, que casi nunca es lo que quería quien llamó. static se resuelve como Post porque esa es la clase nombrada en la llamada; PHP lo llama late static binding. Usa static:: y new static() en métodos pensados para heredarse, y self:: cuando realmente te refieras a esta clase exacta. La misma regla se aplica a las constantes: static::TABLE toma el TABLE propio de una hija, mientras que self::TABLE siempre lee el de la clase donde está escrito el código.
Las propiedades estáticas heredadas se comparten
Una clase hija comparte la propiedad estática de su padre salvo que declare la suya. Es la sorpresa clásica de static: dos subclases contando en un mismo número.
Apples no tiene su propio $count, así que Apples::$count es Counter::$count, y los dos imprimen 2. Pears vuelve a declarar la propiedad y cuenta por su cuenta. Una propiedad estática declarada en un trait se comporta de otra forma: cada clase que usa el trait recibe una copia separada.
Variables estáticas dentro de funciones
static tiene un segundo significado dentro del cuerpo de una función: una variable estática conserva su valor entre llamadas. El valor inicial se asigna solo la primera vez que se ejecuta la función:
El segundo slowSquare(12) se salta el cálculo. Igual que las propiedades estáticas, estos valores se reinician al final de cada petición. La página de variables explica el ámbito de las variables en general.
Cuándo static es la opción equivocada
Los métodos estáticos son cómodos, y eso hace que sea fácil abusar de ellos. Una clase cuyos métodos leen y escriben propiedades estáticas es estado global con un nombre de clase encima: todos los que la llaman lo comparten, los tests no pueden obtener una copia limpia y no puedes sustituirla por otra implementación.
Buenos usos de static: funciones auxiliares puras sin estado (Slug::make()), constructores con nombre (Color::fromHex()) y constantes de toda la clase. Si un método necesita datos que podrían ser distintos entre dos usos, lo que quiere es un objeto.
Preguntas frecuentes
¿Cómo llamo a un método estático en PHP?
Con el nombre de la clase y ::: MathHelper::square(4). Dentro de la misma clase usa self::square(4) o static::square(4). No hace falta ningún objeto, y dentro de un método estático no hay $this.
¿Cuál es la diferencia entre self y static en PHP?
self:: significa siempre la clase donde está escrito el código. static:: significa la clase sobre la que realmente se llamó el método, que puede ser una clase hija; esto se llama late static binding. Así, en un método create() del padre, new self() construye siempre el padre, mientras que new static() construye la hija que lo haya llamado.
¿Qué es una propiedad estática en PHP?
Una propiedad declarada public static int $count = 0; pertenece a la clase, así que hay un solo valor compartido por todos los objetos de esa clase (y de sus hijas, salvo que una hija la vuelva a declarar). Léela y escríbela con ClassName::$count o self::$count; fíjate en el $.
¿Puedo llamar a un método estático sobre un objeto en PHP?
Sí. $obj->square(4) y $obj::square(4) llaman los dos al método estático de la clase del objeto, pero dentro sigue sin haber $this. La dirección que falla es llamar a un método no estático como ClassName::method(): desde PHP 8 lanza un Error.
¿Puedo usar $this en un método estático?
No. Un método estático se ejecuta sin objeto, así que $this no está definido ahí y usarlo lanza un Error ("Using $this when not in object context"). Usa self:: o static:: para llegar a otros miembros estáticos.