Organizar los namespaces de PHP en niveles

  • Por
  • PHP
Alternativas de uso y organización del código PHP por medio de los espacios de nombres: subespacios de nombres, variantes de acceso...

En un artículo anterior pudimos entender el concepto de namespace en PHP y su uso básico. Ahora vamos a seguir explorando posibilidades del lenguaje para sacarle aún más partido y conocer algunas posibilidades un poco más avanzadas.

Vamos a tocar en este texto varios puntos de diversa índole, como la posibilidad de crear subespacios de nombres, organizar los archivos con código, definir un espacio de nombres en varios ficheros diferentes y cosas de este estilo. Todo orientado a que puedas organizar mejor tu código, sacando partido a los namespaces de PHP.

Crear Sub-namespaces

Es habitual que los desarrolladores creen espacios de nombres dentro de otros espacios de nombres. Por ejemplo, todos los namespaces de una empresa o desarrollador pueden comenzar con su "nick" y luego dentro puedes tener espacios de nombres para cada tipo de utilidad que estás desarrollando.

Imagina que DesarrolloWeb.com se dedicase a fabricar librerías con código PHP, pues todas las librerías podrían estar dentro del espacio de nombres "Deswebcom". Luego podríamos tener librerías que se encargan del trabajo con sesiones, cookies, bases de datos, etc. Podrían estar en sub-namespaces como Deswebcom\Sesiones, Deswebcom\Cookies, Deswebcom\BBDD. Ya dentro de Deswebcom\Sesiones podrías tener una serie de clases, funciones y constantes, o a su vez otros espacios de nombres donde organizas otra serie de librerías. El orden es el que tú necesites y esta organización resulta muy popular. De hecho la puedes ver reproducida en numerosos paquetes de librerías o en la organización de las clases de un framework potente.

La definición de los namespaces y sub-namespaces es prácticamente la que hemos comentado en artículos anteriores. Comienzas el código indicando tu namespace (recuerda que debe ser la primera instrucción del archivo).

<?php
namespace Deswebcom\Galaxias\Andromeda;

Como puedes apreciar, la jerarquía de namespaces se indica con una barra invertida (contrabarra). Puede llegar a tantos niveles como necesites y en cada nivel puedes tener miembros del espacio de nombres. Es decir, en el namespace "Deswebcom" puedo tener clases, funciones, constantes, traits, interfaces y otros namespaces. Dentro de los otros namespaces puedo tener otra vez lo mismo: clases, funciones, otros namespaces, etc.

Organizar archivos con namespaces

La organización de tus archivos en espacios de nombres es muy flexible. Hay lenguajes donde a la hora de definir estructuras similares a los namespaces te obligan a que el código resida en carpetas del mismo nombre. En PHP no es así.

Puedes definir namespaces de cualquier profundidad en archivos que tengas en cualquier carpeta. Puedes usar el mismo namespace en diversos archivos, puedes incluso crear varios espacios de nombres en el mismo archivo.

Lógicamente, aunque PHP te permita muchas alternativas, es interesante que tengas tus propias costumbres y una buena práctica sería crear una estructura de carpetas similar a la estructura de espacios de nombres que estás generando. Eso te ayudará a saber dónde están los archivos que tienen el código de cada espacio de nombres.

Cuando trabajas con jerarquías de espacios de nombres puedes encontrar usos como estos que vamos a relatar.

Mismo espacio de nombres en dos archivos diferentes

Si tienes dos archivos que trabajan dentro de un mismo namespace, entonces, las funciones que crees en ambos espacios de nombres estarán disponibles sin declarar que vas a usar ese espacio de nombre.

Puede parecer obvio, pero veamos un ejemplo de dos archivos que trabajan sobre el mismo espacio de nombres. Como primer archivo:

<?php
namespace Deswebcom\Galaxias;

function observar($a){
    echo "Observando la galaxia $a";
}

Como segundo archivo:

<?php
namespace Deswebcom\Galaxias;

//como este archivo está en el mismo espacio de nombres que el anterior
//soy capaz de invocar una función declarada en este namespace sin indicar su ruta
observar("Centaurus A");

Acceso "relativo" a elementos de otros espacios de nombres

Otra cosa que puede surgir es que desde un espacio de nombres quieras acceder a miembros de otro espacio de nombres dependiente.

En este caso ocurre como cuando usas tu sistema de archivos, siguiendo el símil de las carpetas de un disco duro de tu ordenador. Estando situados en un directorio de tu disco duro, pueden surgir tres escenarios:

  1. Acceso a archivos indicando solo su nombre. Es algo que sueles hacer cuando accedes a un fichero que está dentro de la misma carpeta donde te encuentras. En este caso no necesitamos indicar la ruta completa de esos archivos, ya que estamos en el mismo directorio.
  2. Acceso a archivos indicando una ruta relativa. Es el caso que suele ocurrir cuando accedes a archivos que están dentro de subcarpetas de la carpeta donde te encuentras. En este caso como posibilidad podríamos definir la ruta relativa al archivo que queremos acceder, desde la carpeta donde estamos. Osea, si tengo un subdirectorio llamado "folder" y dentro de él hay un archivo "file.txt", podríamos acceder por "folder/file.txt".
  3. Acceso indicando una ruta absoluta. Es el caso típico de acceso a archivos que están en otras rutas no dependientes del directorio donde me encuentro. En este caso lo común y más cómodo es referirnos a los archivos con su ruta absoluta, por ejemplo "/carpeta/subcarpeta/archivo.txt".

Esas mismas situaciones se pueden dar en el uso de namespaces. La primera, acceso a archivos indicando solo su nombre la la hemos visto en el punto anterior, cuando comentábamos que podíamos acceder a funciones definidas en el mismo espacio de nombres como si fueran funciones globales.

La segunda situación la podemos ver en un ejemplo a continuación. Por ejemplo piensa en este espacio de nombres Deswebcom\Galaxias\Andromeda.

<?php
namespace Deswebcom\Galaxias\Andromeda;

function localizar(){
    echo "Soy la galaxia Andromeda y estoy a 3 millones de años luz de la tierra";
}
class Estrella{
    public static function pertenece(){
        echo "Pertenezco a a la galaxia Andromeda";
    }
}

Ahora, si estamos en un espacio de nombres como "Deswebcom\Galaxias", no necesitamos toda la ruta absoluta para llegar a los miembros de "Deswebcom\Galaxias\Andromeda":

<?php
namespace Deswebcom\Galaxias;
include "andromeda.php";

Andromeda\localizar();
Andromeda\Estrella::pertenece();

La tercera posibilidad es también fácil de entender y funcionará siempre, puesto que si indicamos la ruta completa de toda la jerarquía de namespaces, no importa en qué espacio de nombres estamos trabajando. Es decir, indicando el espacio de nombres completo, siempre vamos a poder referirnos a cualquier elemento, independientemente de nuestra posición.

Deswebcom\Galaxias\Andromeda\localizar();
Deswebcom\Galaxias\Andromeda\Estrella::pertenece();
Deswebcom\Galaxias\observar("Via Lactea");

En este caso también admitiría comenzar por una contrabarra toda la ruta jerárquica para el acceso a los namespaces, indicando que el primer namespace "Deswebcom" es de primer nivel.

\Deswebcom\Galaxias\Andromeda\localizar();
\Deswebcom\Galaxias\Andromeda\Estrella::pertenece();
\Deswebcom\Galaxias\observar("Via Lactea");