Php orientado a objetos, parte 8: Propiedades y métodos estáticos

En este posteo explicaré unos de los temas más importantes que tienen que ver con las clases en PHP.

Como hemos visto hasta ahora las clases nos sirven como modelos con un fin: crear objetos. Las clases tienen métodos y estos pueden invocarse desde el objeto que ha sido creado. Sin embargo, las clases no se limitan solamente a eso, servir de modelo para la creación de un objeto.

Dentro de las clases nosotros podemos definir métodos llamados métodos estáticos con la palabra reservada static antes del nombre del método:

class NombreDeLaClase {
    public static function nombreDelMetodo(){
       //
    }
}

Los métodos estáticos a diferencia de los otros se invocan sin crear un objeto, osea desde la misma clase a la que pertenece. De una forma similar a ésta:

NombreDeLaClase::nombreDelMetodo();

Como verán primero se llama a la clase, luego se utliza los dos puntos (::) y finalmente se invoca al método estático creado. Todo esto sin la necesidad de tener que instanciar un objeto basado en esa clase.

Crearé un ejemplo de una clase llamada Date_f, que tendrá dos métodos. Uno que nos devolverá la fecha del día, y otra que nos devolverá la hora.

<?php
 class Date_f {
    public static function getFecha(){
       $anio = date('Y');
       $mes = date('m');
       $dia = date('d');
       return $dia . '/' . $mes . '/' . $anio;
    } 
    public static function getHora(){
       $hora = date('H');
       $minutos = date('i');
       $segundos = date('s');
       return $hora . ':' . $minutos . ':' . $segundos;
    } 
 } 
?>

Y para probarla crearemos un script donde incluiremos la clase y llamaremos a ambos métodos desde la misma. Primero probaremos con el método que devuelve la fecha:

<?php 
 require_once 'clases/Date_f.php';
 echo 'La fecha de hoy es: ' . Date_f::getFecha();
?>

Luego probaremos el método que devuelve la hora:

<?php 
 require_once 'clases/Date_f.php';
 echo 'Son las: ' . Date_f::getHora();
?>

A su vez dentro de un método estático puede llamarse a otro método, siempre y cuando comparte la misma característica: sea estático.

Por ejemplo yo podría crear otro método estático que devuelve la fecha y la hora juntas invocando a los otros dos:

<?php
 class Date_f {
    public static function getFecha(){
       $anio = date('Y');
       $mes = date('m');
       $dia = date('d');
       return $dia . '/' . $mes . '/' . $anio;
    } 
    public static function getHora(){
       $hora = date('H');
       $minutos = date('i');
       $segundos = date('s');
       return $hora . ':' . $minutos . ':' . $segundos;
    }
    public static function getFechaHora(){
       $fecha = self::getFecha();
       $hora = self::getHora();
       return $fecha . ' | ' . $hora;
    }
 } 
?>

Y luego probarlo con:

<?php 
 require_once 'clases/Date_f.php';
 echo 'Fecha y hora: ' . Date_f::getFechaHora();
?>

Para invocar métodos estáticos dentro de la clase no se usa $this->metodo(), sino que lo hago con self::metodo(). Esto se debe a que $this sirve para hacer llamadas a propiedades y métodos que están dentro del objeto (no estáticos), y yo acá no tengo que crear ningún objeto. En realidad self es una palabra reservada que hace referencia al nombre de la clase donde estoy parado, como lo dije anteriormente en mi antiguo posteo, de la misma forma en que se llama a una constante: Php orientado a objetos, parte 5: Constantes.

Osea que hacer:

$fecha = self::getFecha();
$hora = self::getHora();

Es lo mismo que hacer:

$fecha = Date_f::getFecha();
$hora = Date_f::getHora();

Sólo que self es más recomendable por si más adelante decidimos cambiarle de nombre a la clase.

Para llamar a propiedades estáticas también debería hacerse con self. Para eso crearemos una propiedad estática con los días de la semana y un método que los muestre:

<?php
 class Date_f {
    private static $dias_de_la_semana = array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo');
    public static function getFecha(){
       $anio = date('Y');
       $mes = date('m');
       $dia = date('d');
       return $dia . '/' . $mes . '/' . $anio;
    } 
    public static function getHora(){
       $hora = date('H');
       $minutos = date('i');
       $segundos = date('s');
       return $hora . ':' . $minutos . ':' . $segundos;
    }
    public static function getFechaHora(){
       $fecha = Date_f::getFecha();
       $hora = Date_f::getHora();
       return $fecha . ' | ' . $hora;
    }
    public static function mostrarDíasDeLaSemana(){
       $cadena_con_dias = implode(', ', self::$dias_de_la_semana);
       return $cadena_con_dias;
    }
 } 
?>

Cómo ven creamos un nuevo método que devolverá una cadena con los días de la semana y los recupera llamando a la propiedad estática $dias_de_la_semana:

<?php 
 require_once 'clases/Date_f.php';
 echo 'Los días de la semana son: ' . Date_f::mostrarDíasDeLaSemana();
?>

Otra cosa que vale aclarar es que dentro de un método estático no se puede invocar un método que no lo es, ya que estos sólo están disponibles en el momento en que se crea un objeto. Sí en cambio podemos retornar desde un método estático un objeto basado en la clase. Por ejemplo nosotros podemos tener una clase con este aspecto:

<?php 
 class Persona { 
    private $nombre;
    private $apellido;
    private $edad;
    public function __construct($nombre, $apellido, $edad) {
       $this->nombre = $nombre;
       $this->apellido = $apellido;
       $this->edad = $edad;
    }
    public function saludar(){
       return 'Hola, soy ' . $this->nombre . ' ' . $this->apellido . ' y tengo ' . $this->edad . ' años '; 
    }
    public static function getUsuarioPorDefecto(){
       return new self('Fernando', 'Gaitan', 26);
    }
 }
?>

Pero en lugar de utilizar el constructor para crear el objeto, creamos instancia con un método estático de esta forma:

<?php 
 require_once 'clases/Persona.php';
 $persona = Persona::getUsuarioPorDefecto();
 echo $persona->saludar();
?>

Al trabajar en forma independiente de un objeto los métodos estáticos se caracterizan por ser similares a las funciones, pero la ventaja que tiene sobre ésta es que cada método estáticos está encapsulada en una clase. Esto nos permite trabajar en forma más ordenada que la programación estructurada, en donde a medida que el proyecto iba haciéndose más grande y terminábamos teniendo millones de funciones esperando ser invocadas.

Anterior: Php orientado a objetos, parte 7: Clases abstractas y finales

Siguiente: Php orientado a objetos, parte 9: Excepciones


3 Respuestas a “Php orientado a objetos, parte 8: Propiedades y métodos estáticos”

  1. Hola fernando,
    Primero antes que nada te quiero felicitar por lo claro que sos con las explicaciones y ademas tu pagina tiene exelentes contenidos.

    Entiendo que si es posible dentro de un metodo estatico llamar a propiedades o metodos estaticos con la palabra reservada self y el operador :: segudio de el metodo o la propiedad estatica y por fuera de la clase sin instanciar el objeto es posible llamar con el nombre de la clase seguido del operador :: y metodo o el nombre de la propiedad como variable.

    Segun lo que investigue es que, dentro deuna clase en un metodo no static es posible llamar a propiedades y metodos estaticos. Puesto que es posible instanciar en la clase y llamar a este dicho metodo para que llamase a las propiedades y metodos estaticos.

    Mi duda es la siguiente dentro de la clase si tengo un metodo estatico
    ¿es posible llamar a propiedades y metodos no estaticos?

    Gracias
    Saludos

    1. De hecho no. A ver, por un segundo olvidate del concepto de estático, hacé de cuenta que no existen ni los atributos, ni los métodos estáticos.

      Quién se llama Ramiro? Quién programa? VOS. Vos sos el objeto, Ramiro es el valor de un atributo nombre, y programar es un comportamiento tuyo. Si vos existís, vos podés llamarte Ramiro, y vos podés programar, pero alguien tiene que ser y hacer para que esos atributos y métodos existan.

      Osea dentro de un método estático a qué atributo o método (estáticos) estarías llamando, si no tenés un objeto definido.

      Sí en cambio podés devolver dentro de un método estático, un objeto de la clase.

      Saludos!

      1. Claro tenes razón no lo pensé de esa manera, la verdad me terminaste de aclarar el concepto.

        Quería aprovechar el comentario para hacerte una consulta y un favor.

        la consulta va para los métodos y clases finales. Entiendo que una clase definida como final sus métodos se consideraran finales sin necesidad de anteponer la palabra reservada final en estos. Esta clase no permitirá ser heredada y por lógica sus métodos no podrán ser modificados. Mi pregunta es si la clase no se define como final pero contiene métodos finales.

        ¿Es posible heredar la clase aunque tenga métodos finales, teniendo en cuenta que las clases finales no podrán heredar?

        Por otro lado opino que la clase no fue definida como final pero si sus métodos por lo que se podrá heredar, pero la clase que reciba la herencia en sus métodos solo se podrán llamar a los métodos finales y no se podrán modificar. Pero como digo es una opinión y no una afirmación.

        Y respecto al favor quería pedirte si podrás hacer una próxima entrega acerca de interface-implements que un contenido mas a la temática de la programacion orientada a objetos.

        Muchas gracias Saludos