Curso de PHP
Atributos y métodos estáticos en PHP
Por Víctor Peña · Publicado el

Hola, ¿cómo están? Continuando con el curso de PHP, hoy veremos los atributos y métodos estáticos: los que pertenecen a la clase en lugar de a cada objeto.
¡Empecemos!
Qué significa estático
Hasta ahora, cada objeto tenía sus propios valores. Si creabas dos mascotas, cada una llevaba su nombre.
Un miembro estático es distinto: pertenece a la clase, no a los objetos. Existe uno solo, compartido por todos, y se puede usar sin haber creado ningún objeto.
Propiedades estáticas
Se declaran con static y se acceden con :::
<?php
class Contador
{
public static int $total = 0;
public function __construct()
{
self::$total++;
}
}
new Contador();
new Contador();
new Contador();
echo Contador::$total; // 3
Fíjate en dos cosas:
- Dentro de la clase se usa
self::$total, no$this->total.$thisse refiere al objeto;selfa la clase. - Desde fuera se usa
Contador::$total, sin necesidad de ningún objeto.
Y fíjate en el efecto: los tres objetos comparten el mismo contador. No hay tres copias, hay una.
Métodos estáticos
<?php
class Matematicas
{
public static function sumar(float ...$numeros): float
{
return array_sum($numeros);
}
public static function promedio(float ...$numeros): float
{
return self::sumar(...$numeros) / count($numeros);
}
}
echo Matematicas::sumar(10, 20, 30); // 60
echo Matematicas::promedio(10, 20, 30); // 20
No hace falta new. Se llama directamente sobre la clase.
Aquí aparecen los argumentos variádicos: float ...$numeros acepta cuantos argumentos le pases y los recibe como array. Y al llamar, ...$numeros los vuelve a desempaquetar.
$this no existe en un método estático
Es la limitación clave, y tiene toda la lógica: si el método pertenece a la clase y no a un objeto, no hay ningún objeto al que referirse.
<?php
class Ejemplo
{
private string $nombre = "Víctor";
public static function saludar(): string
{
return $this->nombre; // Error fatal: $this no existe aquí
}
}
Un método estático solo puede usar propiedades estáticas.
self, static y parent
Tres formas de referirse a clases dentro de una clase:
<?php
class Padre
{
public static function crear(): static
{
return new static(); // la clase real que llamó
}
public static function crearFijo(): self
{
return new self(); // siempre Padre
}
}
class Hijo extends Padre {}
var_dump(Hijo::crear()); // object(Hijo)
var_dump(Hijo::crearFijo()); // object(Padre)
selfse resuelve en la clase donde está escrito.staticse resuelve en la clase que realmente se invocó. Se llama late static binding.parentapunta a la clase padre.
En general quieres static, porque permite que las clases hijas funcionen correctamente. self solo cuando deliberadamente quieras fijar la clase.
El patrón más útil: constructores con nombre
Este es probablemente el mejor uso cotidiano de los métodos estáticos:
<?php
declare(strict_types=1);
class Dinero
{
private function __construct(
private readonly int $centavos,
private readonly string $moneda,
) {}
public static function desdeBolivianos(float $monto): static
{
return new static((int) round($monto * 100), 'BOB');
}
public static function desdeCentavos(int $centavos): static
{
return new static($centavos, 'BOB');
}
public static function cero(): static
{
return new static(0, 'BOB');
}
public function formatear(): string
{
return number_format($this->centavos / 100, 2) . ' ' . $this->moneda;
}
}
echo Dinero::desdeBolivianos(150.75)->formatear(); // 150.75 BOB
echo Dinero::cero()->formatear(); // 0.00 BOB
Fíjate en que el constructor es privado: la única forma de crear un objeto es a través de los métodos estáticos, cuyos nombres dicen exactamente qué esperan recibir. Dinero::desdeBolivianos(150.75) es infinitamente más claro que new Dinero(15075, 'BOB').
Y de paso, esto resuelve el problema del dinero con decimales que mencionamos en la lección de operadores aritméticos: internamente se guarda en centavos como entero.
Constantes de clase
Las constantes que vimos en la lección de constantes también se acceden con :::
<?php
class Pedido
{
public const ESTADO_PENDIENTE = 'pendiente';
public const ESTADO_PAGADO = 'pagado';
public static function estadosValidos(): array
{
return [self::ESTADO_PENDIENTE, self::ESTADO_PAGADO];
}
}
echo Pedido::ESTADO_PAGADO;
print_r(Pedido::estadosValidos());
Cuándo usar estáticos
Buenos usos:
- Funciones utilitarias sin estado: formatear, validar, convertir.
- Constructores con nombre, como el ejemplo de
Dinero. - Contadores o registros compartidos por todas las instancias.
- Constantes de clase.
Malos usos:
- Guardar el estado de la aplicación en propiedades estáticas.
- Como sustituto de pasar dependencias.
Por qué conviene no abusar
Aquí hay algo importante que casi ningún tutorial menciona.
Una llamada estática ata tu código a una clase concreta:
<?php
class ServicioDePedidos
{
public function confirmar(int $id): void
{
Mailer::enviar("Pedido $id confirmado"); // atado
}
}
Compáralo con lo que vimos en interfaces: si en lugar de la llamada estática recibes un Mailer por constructor, puedes sustituirlo en pruebas o cambiar de proveedor sin tocar esta clase. Con la llamada estática, no puedes.
Además, el estado estático se comparte durante toda la ejecución. Si una parte del programa lo modifica, las demás lo ven. Es una variable global con otro nombre, y trae los mismos problemas: comportamiento impredecible y errores difíciles de reproducir.
La regla práctica: usa estáticos cuando el método no dependa de ningún estado. Si necesita datos o colaboradores, mejor un objeto normal.
Un ejemplo práctico
<?php
declare(strict_types=1);
class Validador
{
public static function email(string $valor): bool
{
return filter_var($valor, FILTER_VALIDATE_EMAIL) !== false;
}
public static function telefonoBoliviano(string $valor): bool
{
return preg_match('/^[67]\d{7}$/', $valor) === 1;
}
public static function noVacio(?string $valor): bool
{
return $valor !== null && trim($valor) !== '';
}
}
$datos = [
'correo' => 'cliente@empresa.com',
'telefono' => '76980507',
'nombre' => '',
];
var_dump(Validador::email($datos['correo'])); // true
var_dump(Validador::telefonoBoliviano($datos['telefono'])); // true
var_dump(Validador::noVacio($datos['nombre'])); // false
Este es el caso ideal para estáticos: funciones puras que reciben un valor, devuelven un resultado y no guardan nada.
Errores comunes
- Usar
$thisdentro de un método estático. - Usar
->en lugar de::para acceder a un miembro estático. - Olvidar
self::al usar una propiedad estática dentro de la clase. - Guardar estado de la aplicación en propiedades estáticas.
- Usar
selfdonde tocabastatic, rompiendo el comportamiento en las clases hijas.
Para cerrar
Los miembros estáticos pertenecen a la clase y existen sin necesidad de crear objetos. Son perfectos para utilidades sin estado y para constructores con nombre; peligrosos cuando guardan información que cambia.
La pregunta antes de declarar algo estático: ¿esto depende de algún dato del objeto? Si la respuesta es sí, no debería serlo.
En la siguiente lección veremos los arrays en profundidad.
Saludos y éxitos.
Norvic Software
Desarrollamos el software que tu empresa necesita
Somos una fábrica de software en Bolivia. Construimos sistemas a medida y aplicaciones móviles, y llevamos Inteligencia Artificial a las empresas que ya tienen un sistema funcionando.
- Chatbots con Inteligencia Artificial
- Creación de agentes de IA
- Integración de IA en tus sistemas
- Desarrollo de software a medida
- Aplicaciones móviles iOS y Android
- Consultoría y asesoramiento técnico
Cotización sin costo · Respuesta directa por WhatsApp