viernes, 29 de febrero de 2008

Metadata en nombres de archivos PHP

Por suerte con PHP no hay restricciones o estandares a seguir con respecto al nombrado de los archivos PHP. Algo que no es nada nuevo es que podemos usar el nombre del archivo para comunicar más información que solo el nombre del archivo. Algo muy usado es ponerle "archivo.class.php" o directamente "archivo.class" a los archivos PHP que contienen una o más clases. Se puede notar que ni siquiera es requerido que el archivo tenga extensión ".php".

A continuación voy a mostrar algunos ejemplos de nombrado de archivos que pueden ser de utilidad al implementar aplicaciones.


1. Paquetes codificados en el nombre del archivo

PHP no soporta paquetes, lo que es un dolor de cabeza para la implementación de aplicaciones de cierto tamaño. Hay muchas formas de simular la presencia de paquetes en PHP, en este caso se hace con el nombrado de los archivos.

Los paquetes son una setructura jerárquica similar a una estructura de directorios, lo paquetes pueden contener archivos y otros paquetes. Por ejemplo, en Java, los paquetes coinciden con la estructura de directorios en donde se encuentran los archivos (paquetes físicos), en cambio, en C# se pueden definir una especie de paquetes lógicos llamados "namespaces".

Usando el nombre de los archivos para codificar paquetes lógicos nos evitamos problemas como tener dos archivos con el mismo nombre, o simplemente tener un poco más de orden cuando trabajamos con gran cantidad de archivos, y se podrían tener una inmensa cantidad de archivos, en el mismo directorio, perfectamente distinguidos entre si y fáciles de encontrar a simple vista.

Digamos que en nuestro proyecto tenemos 3 paquetes: "core", "core.utils", "core.db". Por otro lado tenemos 100 archivos, 20 del paquete "core", 40 de "core.utils" y otros 40 de "core.db". Y llamamos a los archivos dentro de estos paquetes de la siguiente forma:

- core.UnArchivo.php
- core.OtroArchivo.php
- ...
- core.utils.UnArchivo.php
- core.utils.OtroArchivo.php
- ...
- core.db.MySQL.php
- core.db.PostgreSQL.php
- ...

En principio, estos nombres pueden servir para ver de forma simple que archivos están en que paquete, simplemente listando los archivos ordenados por nombre.

Otra ventaja, ya desde el punto de vista del sistema que estemos construyendo, es por ejemplo hacer un script para cargar o incluir todos los archivos de determinado paquete, por ejemplo, la siguiente función incluye todos los archivos del paquete:

function includeDB( $path )
{
$d = dir($path);

while (false !== ($entry = $d->read())) // Por cada entrada del directorio
{
if (is_file($path . "/" . $entry)) // Si la entrada es un archivo
{
if ( strcmp("core.db", substr($entry,0,7)) == 0 ) // Si el nombre empieza con "core.db"
{
include_once($path . "/" . $entry); // Lo incluye para usarlo
}
}
}
}

Explicación del código:

$path es la ruta del directorio que contiene los archivos. No se verifica que sea correcta, esta verificación se podría agregar para hacerlo mas robusto.

$entry son los archivos del directorio.

Lo demás ya se explica con los comentarios en el código.


Tambien se podria usar el nombrado para hacer un class loader (como el del codigo anterior) mas inteligente, sin necesidad de incluir todos los archivos del sistema, si no incluyendo solo los que se van a usar.



2. Decir que contiene el archivo

Un archivo php puede contener cualquier cosa, ya que no es mas que un archivo de texto.

Pensando en alguno de los posibles contenidos que puede tener un archivo php podría nombrar:

- scripts (en el sentido de tener un código que se ejecuta automáticamente al cargar el archivo)
- funciones
- clases
- interfaces
- paginas (código HTML mezclado con script PHP)

Entonces, podríamos utilizar el nombre del archivo para decir que tipo de contenido tiene, en los casos anteriores podríamos tener los siguientes nombres:

- DownloadFile.script.php
- String.functions.php
- Invoice.class.php
- Clonable.interface.php
- Contacts.page.php


También, esta notación puede servir para saber a simple vista que tiene cada archivo, o también para cargar los archivos por su tipo, por ejemplo si quiero cargar todas las clases de un determinado directorio, puedo usar el código anterior y modificarlo un poco y buscar los archivos que tienen "class" adelante del ".php" como en el siguiente ejemplo:

function includeDB( $path )
{
$d = dir($path);

while (false !== ($entry = $d->read())) // Por cada entrada del directorio
{
if (is_file($path . "/" . $entry)) // Si la entrada es un archivo
{
if ( preg_match("/(.*)class\.php$/", $entry, $matches) ) // Si el nombre tiene "class" antes del ".php"
{
include_once($path . "/" . $entry); // Lo incluye para usarlo
}
}
}
}


Una posible aplicacion de esto es si uno tiene scripts de testing para correr, y algun otro script encargado de correr los tests, y los test se llaman por ejemplo "paquete.Nombre.test.php", puedo buscar todos los tests, incluirlos, correrlos y mostrar los resultados. A simple vista se puede ver el poder con el que se cuenta simplemente por nombrar los archivos de cierta forma.


3. Paquetes y contenido

Y podemos también decir en que paquete esta un archivo y ademas poner que tipo de contenido tiene, por ejemplo:

- core.db.MySQL.class.php
- core.String.functions.php
- ...


Conclusión:

Podemos utilizar los nombres de los archivos para poner metadatos que nos dan información sobre el archivo, que lugar ocupa o que responsabilidad tiene en el sistema y que tipo de contenido tiene. Esa información la podemos utilizar para hacer sistemas mejores, mas eficientes, mas potentes, etc, ademas de que es una buena forma de ordenar los archivos cuando tenemos un gran numero de ellos. Y como vimos es muy simple hacer scripts que procesen los nombres de los archivos, utilizando funciones del file system como dir() para leer nombres de archivos y funciones de strings o expresiones regulares para filtrarlos.

1 comentario:

  1. Con la version 5.3.0 parece que fueron implementados los namespaces por lo que no podria tener 2 clases con el mismo nombre en la misma aplicacion, pero en distintos namespaces.

    What's new in PHP 5.3?

    ResponderEliminar