Usando Constantes en El Software

Una buena práctica en el desarrollo software es el uso de constantes y en este post os voy a intentar dar mi punto de vista sobre como usarlas de un modo correcto y como nos pueden ayudar a escribir un código más limpio y reutilizable.

¿Que es una constante?

Una constante, tal y como su nombre indica, es un valor que no varía durante el tiempo, es decir, solamente puede ser leído. Se diferencian de las variables ya que estas sí que varían durante el tiempo. Las constantes una vez definidas no pueden ser modificadas y permanecerán con el valor inicial durante toda la ejecución.

Ejemplo de constante

Para seguir con la explicación voy a hacerlo mediante un ejemplo de código. Supongamos que tenemos una clase Car y esta contiene un atributo speed que será un entero con la velocidad del coche.

<?php

final class Car {
	
    private $speed;

    public function __construct()
    {
        $this->speed = 0;
    }

    public function speed(): int
    {
        return $this->speed;
    }
}

Dicho coche tendrá la capacidad de acelerar y frenar. Así pues tendremos dos métodos publicos tanto para acelerar como para frenar.

<?php

final class Car {
	
    private $speed;

    public function __construct()
    {
        $this->speed = 0;
    }

    //...

    public function accelerate(): void
    {
        $this->speed++;
    }

    public function decelerate(): void
    {
        $this->speed--;
    }
}

Una vez aquí, desde negocio, nos dicen que nuestro coche tendrá dos restricciones en cuanto al valor de la velocidad. La primera restricción es que nuestro coche solo tendrá velocidad positiva (nunca podrá ir a una velocidad menor que 0 km/h) y la segunda restricción es que nuestro coche no puede sobrepasar la velocidad de 100 km/h.

Para dar solución a estas nuevas restricciones podríamos simplemente modificar el código tal que así:

<?php

final class Car {
	
    private $speed;

    public function __construct()
    {
        $this->speed = 0;
    }

    //...

    public function accelerate(): void
    {
    	if ($this->speed < 100) {
            $this->speed++;
    	}
    }

    public function decelerate(): void
    {
        if ($this->speed > 0) {
            $this->speed--;
        }
    }
}

El código nuevo cumpliría satisfactóriamente con los requisitos, pero ¿qué problemas vemos en este trozo?

Para solventar estos problemillas podemos hacer uso de las constantes. Así quedaría nuestro código:

<?php

final class Car {

    const MAX_SPEED_ALLOWED = 100;
    const MIN_SPEED = 0;
	
    private $speed;

    public function __construct()
    {
        $this->speed = 0;
    }

    //...

    public function accelerate(): void
    {
    	if ($this->speed < self::MAX_SPEED_ALLOWED) {
            $this->speed++;
    	}
    }

    public function decelerate(): void
    {
        if ($this->speed > self::MIN_SPEED) {
            $this->speed--;
        }
    }
}

¿Como lo hemos arreglado?

No solo para enteros

También deberíamos usar estas constantes en los strings que tengamos por el código. Un ejemplo típico es:

<?php

final class PostStatus
{
    const PUBLISHED = 'published';
    const UNPUBLISHED = 'unpublished';

    private $status;
    
    private function __construct(string $status)
    {
       $this->status = $status; 
    }

    public static function fromPublished(): self
    {
        return new static(self::PUBLISHED);
    }

    public static function fromUnpublished(): self
    {
        return new static(self::UNPUBLISHED);
    }
}

Bonus

A partir de la versión de PHP 7.1 podemos añadir visibilidad (public, protected y private) a las constantes de clase. Por lo tanto podemos tener constantes visibles des de fuera de la propia clase (public), visibilidad solo para los hijos (protected) o visibilidad solo para la propia clase (private).

<?php

final class Car
{
    public const MAX_SPEED_ALLOWED = 100;
    protected const MIN_SPEED = 0;
    private const NAME = 'Ferrari';
	
    public function __construct($spe)
    {
        $this->speed = 0;
    }
}

Car::MAX_SPEED_ALLOWED // Devuelve 100
Car::MIN_SPEED // Lanza error
Car::NAME // Lanza error

Más info en la web de php