En este primer capítulo vamos a ver los namespaces en PHP y Namespaces de PHP en Drupal, un concepto básico de orientación a objetos. Si ya sabes de que van los namespaces y el autoload, puedes ir directamente al final.

La orientación a objetos consiste en encapsular funcionalidades y modularizar un sistema lo más posible con afán de re-aprovechar código y dotarlo de una estructura lógica, clara y concisa. Eso se traduce en una cantidad absurda de archivos que contienen clases con sus atributos y métodos. ¿Cómo lo hacemos para poner nombre a tantos archivos y que PHP encuentre lo que estamos invocando sin error?

Los que habéis trabajado con Drupal 7 conocéis de sobra el problema de la colisión de nombres de funciones. Cuando definimos hooks en Drupal 7, evitamos la colisión poniendo como prefijo el nombre de nuestro módulo de la siguiente forma:

No solo lo hacemos con los hooks, también lo hacemos con el resto de funciones auxiliares añadiendo un guión bajo al principio.

Esto es así porque en Drupal 7, cuando activamos un módulo, su código se carga en cada ejecución. De esa forma, se consigue que el código esté siempre disponible siempre que nuestro módulo esté habilitado. Si no prefijáramos las funciones, tendríamos que buscar nombres de función muy rebuscados para evitar colisiones entre distintos módulos.

Vamoh a calmarnoh

Los que no vengáis de Drupal 7 (y algunos de los que sí), debéis tener los dientes rechinando ahora mismo. Sí, amigos. ¡Ese módulo de 3000 líneas de código tan chulo que hicisteis para ese proyecto se carga en memoria incluso en peticiones donde no se utiliza!¡El horror!¡El horror!

Con la llegada de la orientación a objetos en Drupal 8, este problema se solventa. Gracias a que repartimos el código en distintas clases y plugins, Drupal sabe cuando tiene que cargar una clase o no. Eso lo conseguimos gracias a los namespaces y la sentencia “use” (y un poquito de magia negra).

La idea básica de los namespaces es darle nombre y apellidos a nuestra clase. De esta forma, podemos invocarla de forma unívoca en nuestro código sin temor a colisiones. Y lo que es mejor: ¡podemos darle el nombre que queramos a las funciones de clase y olvidarnos de las colisiones!

Anatomía de un Namespace

Un namespace normalmente se define con la palabra clave “namespace” seguido del “nombre completo” de nuestra clase. Ejemplo:

El namespace será siempre la primera línea de código de nuestra clase. En esta declaración estamos definiendo el namespace al que pertenece nuestra clase, que sería:

  • “Foo\Bar\MiClase”

Además, si tuvieramos atributos o métodos estáticos (hablaremos de ellos más adelante), estos también tendrían nombre:

  • “Foo\Bar\MiClase::metodoDeClase()”
  • “Foo\Bar\MiClase::$atributoDeClase”

El primero es el “nombre completo” del método de la clase y el segundo el del atributo (importante el “$” delante del nombre).

Vale, ¿y ahora qué hacemos con esto?

A veces en Drupal 7 necesitamos cargar librerías de PHP externas. O hacemos archivos PHP a parte para estructurar nuestro código un poco mejor. Cuando eso pasa, solemos utilizar el include, el require o sus primos que se apellidan “once”. Con orientación a objetos ya no hace puñetera falta. Simplemente escribimos el nombre de nuestra clase y a tirar millas:

De esta manera, PHP ya sabe qué tiene que hacer cuando ponemos ese nombre. Cuando usamos así los namespaces, hay que recordar poner la primera contrabarra para indicar el nombre completo desde la raíz.

Esto puede ser muy engorroso de leer, pero por suerte en PHP tenemos la sentencia antes mencionada: “use”. Con esa sentencia, podemos definir al principio del archivo las clases que usaremos. Esta sentencia la pondremos debajo del namespace para cada clase que usemos. A partir de entonces, en cualquier punto de nuestro archivo podemos invocar a la clase simplemente por el nombre de clase.

En este caso, tenemos que poner el nombre completo de nuestra clase en la sentencia “use”. En el “use” no hace falta poner la primera contrabarra, se supone que el use es desde la raíz del proyecto.

Luego en el código, simplemente escribiendo el nombre de la clase, PHP sabrá a qué nos estamos refiriendo. En la sentencia “use” podemos definir alias para nuestras clases y así referirnos a ellas con otro nombre en nuestro código, pero todavía no he encontrado un caso en Drupal 8 donde esto fuera necesario.

Básicamente la sentencia se escribiría como:

A partir de aquí, en lugar de invocar “new MiClase()” podríamos usar “new ClaseMolona()”.

Autoloading y otras formas de brujería

Antes he dicho que PHP sabía lo que tenía que hacer al poner el “use” o usar el namespace completo de nuestra clase, pero eso no es del todo cierto. Al usar “include” o “require” solíamos poner la ruta completa hasta nuestro archivo de código. Con los namespaces, estamos poniendo un nombre arbitrario. ¿Como sabe PHP donde está el archivo con el código de nuestra clase?

Para eso, tenemos el Autoload o autocarga de Clases. Esto es un mecanismo que permite al desarrollador definir una o varias funciones de autocarga que básicamente se encargan de traducir un namespace al una estructura del sistema de ficheros. De este modo, podemos definir una estructura arbitraria de clases y delegar en nuestras funciones de autoload el descubrir donde está el código de cada una. Al invocar una clase por namespace o a través del “use”, PHP usará estas funciones para localizar el código y cargarlo en memoria.

Dicho de una forma más clara y concisa, el autoloading nos ayuda a traducir un namespace a un sistema de ficheros. Por ejemplo, imaginemos que nuestro proyecto reside en el directorio “/var/www/miproyecto/”. En nuestra función de autoload podríamos definir el namespaces “MiProyecto” y hacer que apuntase a ese directorio. A partir de ahí, cualquier nombre del namespace apuntaría o bien a un directorio si no es un nombre final o bien a un fichero si sí lo es.

De esta forma, cuando creáramos la clase “MiClase” en la raíz, su namespace sería “MiProyecto/MiClase” y eso apuntaría al fichero que está en la ruta “/var/www/miproyecto/MiClase.php”. Si tuvieramos un namespace como “MiProyecto/MiClase/Formularios/MiFormulario.php”, la ruta del archivo sería “/var/www/miproyecto/Formularios/MiFormulario.php”.

Se complica la cosa al tener que definir estos autoloads, ¿eh? No te preocupes joven programador de Drupal 7. Afortunadamente para ti, esa parte del trabajo ya está hecha en Drupal 8. Tú solo tienes que preocuparte de hacer las cosas como tocan.

Namespaces en módulos de Drupal 8

Drupal 8 tiene definidas una serie de funciones de autoload que nos ayudarán en nuestro día a día. Si seguimos una serie de convenciones, solamente tendremos que preocuparnos de declarar los namespaces y los use en nuestras clases y poco más.

Al crear un nuevo módulo en Drupal 8, automáticamente este tendrá un namespace base que será “Drupal\nombre_modulo”. Cualquier clase que creemos en nuestro módulo, tendremos que crearla dentro de este namespace.

Ese namespace además apunta al directorio “src” de nuestro módulo. De esta forma, si el módulo se llama “mi_modulo” y creamos en su directorio “src” la clase de ejemplo anterior, su namespace sería

  • “Drupal\mi_modulo\MiClase”

Otro ejemplo: Crear un formulario usando la Form API de Drupal 8 se hace creando una clase que extiende la clase “FormBase”. La convención de Drupal para los formularios es que debería estar en el directorio “Form” dentro del “src”. Si su nombre de clase fuera “MiFormulario” su namespace seria:

  • “Drupal\mi_modulo\Form\MiFormulario”

¿Vais viendo el patrón? Pues esto mismo se aplica a cualquier parte del código de Drupal, incluidos módulos contribuidos o el Core. La única diferencia con el core (namespace “Drupal\Core”) es que sus clases se encuentran en el directorio “core/lib/Drupal/Core”.

Por lo tanto, la clase EntityTypeManager que se usa para cargar entidades (en lugar del antiguo “node_load”) que tiene como namespace “Drupal\Core\Entity\EntityTypeManager” tiene su código en “core/lib/Drupal/Core/Entity/EntityTypeManager,php”.

Esto viene a significar que solamente por su namespace deberíais poder encontrar con facilidad la clase a la que se hace referencia, podéis ver su código y trabajar con ella con comodidad.

Resumiendo (tl;dr;)

Los namespaces:

  • Nos ayudan a evitar colisiones e identificar unívocamente nuestro código sin necesidad de nombres largos y complejos en las funciones.
  • Nos ayudan a encontrar fácilmente el código PHP gracias a las convenciones de autoload.
  • Se tienen que definir al principio de nuestras clases.
  • Sirven para invocar nuestra clase mediante la sentencia “use” al principio de nuestra clase o directamente en el código con el nombre completo.

Si queréis profundizar más en el tema (mismos links que en el texto), un par de enlaces:

Y por supuesto, para cualquier sugerencia del post, pregunta, duda o aclaración, usad los comentarios y estaré encantado de responderos 🙂

Categorías: Drupal

Deja un comentario

Entradas relacionadas

Drupal

D8 para D7 developers: Introducción

Hace pocos meses se ha publicado la versión 8 de Drupal. Llevo trabajando con Drupal de forma profesional desde hace ya diez años. He tocado todas las versiones desde la 4.7 que empezó a ganar Leer más…

A %d blogueros les gusta esto: