Uno de los problemas que me he encontrado
con la versión 5 de PHP es la falta de la representación de los
"paquetes" desde el propio lenguaje de
programación.
Lamentablemente la versión
beta de PHP5 incluía el soporte a este "concepto" pero aparentemente los
desarrolladores no pudieron completar esta característica a tiempo y
tuvieron que quitar el soporte en la versión final y prometerlo para la
próxima versión 6.
En el contexto de UML,
un "paquete" es un "agrupador" de elementos de la Programación
Orientada a Objetos. Estos elementos pueden ser clases, interfaces,
otros paquetes, etc.
En la mayoría de las tecnologías que usan la OO la
representación "física" corresponde directamente con un "subdirectorio" de
nuestro sistema de archivos (filesystem). Es decir, cada paquete es una
carpeta más que agrupa otros archivos (que representarán a su vez clases,
interfaces, etc).
Cuando hablamos de un diseño en
"3 capas", nos referimos a que
conceptualmente tendremos separado nuestro sistema en "3 zonas" con
responsabilidades o tareas distintas a cumplir.
¿Cual es el beneficio de esta separación?
La división en capas reduce la complejidad,
facilita la reutilización y acelera el proceso de ensamblar o desensamblar
alguna capa, o sustituirla por otra distinta (pero con la misma
responsabilidad).
Lo
tradicional es que tendremos la capa de "Presentación" (o GUI, Interfaz, etc),
la capa de "Dominio" (donde verdaderamente se resuelve el
"problema",
también llamada "Lógica de Negocio") y la capa de
"Persistencia" (o
cualquier otro nombre que se nos ocurra: "Capa de Acceso a Datos", etc)
donde se resuelve el almacenamiento o recuperación de la información (puede
ser una Base
de Datos, un archivo XML,
un Webservices,
etc).
Si volvemos a UML, la forma que tenemos de representar esta separación en
capas es a través de "paquetes". Pasando en limpio, una "capa de
responsabilidad" es un "paquete" que por principio de diseño *siempre* tiene
una única responsabilidad (y su nombre la describe).
¿Cómo se hace en otras tecnologías?
En
tecnologías como .Net o Java,
cuando se crea un "paquete" nuestro entorno de desarrollo genera la sintaxis
de forma automática y comienza a agrupar de forma gráfica todas las clases
que vayamos a agregar dentro.
La gran ventaja "no aparente" es que nos evita tener que hacer
referencias físicas a los subdirectorios correspondientes. Este problema
surge cuando usamos otro tipo de lenguaje que no implementa este concepto, y
ahí aparecen los primeros problemas
¿Cómo hacemos en PHP5?
Tanta publicidad de nuestra parte para apoyar a esta nueva versión que
incorpora las nuevas características de la OO, que lo hace subir de nivel,
obtener más respeto de los desarrolladores OO...
y no soporta el concepto de "paquetes"!!! ;
Intentaremos una solución. Si conceptualmente separamos nuestro sistema en 3
capas, nuestro problema se debería resumir en un manejo de subdirectorios:
debo crear 3 subdirectorios y estos deben poder ser referenciados desde
cualquier lugar sin mayor dificultad.
Hago hincapié en esto porque podemos cometer varios errores si subestimamos
el problema.
Si lo solucionamos con
"referencias absolutas", nuestro sistema queda "hardcoded"
y dificultamos el cambio de lugar físico a nuestra aplicación. Si intentamos
hacer todas "referencias relativas", como dice su palabra, dependerán de
donde son invocadas estas referencias para que funcionen o no (por eso son
"relativas").
Ejemplos
// Ejemplo de "referencia absoluta"
require_once '/var/www/aplicacion/persistencia';
// Ejemplo de "referencia relativa"
require_once 'persistencia/BD.class.php';
Este último caso funcionará solo si el fuente que invoca esta sentencia se
encuentra posicionado en la raíz del proyecto.
Si estamos dentro del
subdirectorio "dominio", deberíamos bajar un nivel y subir al nivel
del subdirectorio
require_once '../persistencia/BD.class.php';
Una solución que se hace abitualmete (sin tener que implementar un sitio
modular) es que exista un archivo configuración.php con
referencias a todos los "paquetes" del sistema e incluirlo en todos los
fuentes que necesiten usarlos.
Una opción puede ser crear una sesión y
luego variables de sesión con las referencias a los directorios, y la
segunda, sin usar una sesión, cargando la información en constantes.
Otra solución teórica que veo a este problema es invocar el archivo de
configuración definiéndolo en la propia configuración de PHP (php.ini) para
que lo incluya en todos los fuentes sin necesidad de escribir línea alguna.
Lo negativo es que ahorramos una línea de invocación pero obligamos a todos
los fuentes tener acceso a esta información ... lo que hace que conozcan más
de lo que deberían (otro principio de diseño).
Pero bueno, "la peor gestión es la que no
se realiza" ... entonces, continuemos.
Ejemplos
Código de configuración.php con uso de
sesiones
$_SESSION['HOME']= $_SERVER[DOCUMENT_ROOT];
$_SESSION['APLICA']= $_SESSION['HOME']."/aplicacion";
$_SESSION['DOM']= $_SESSION['APLICA']."/dominio";
$_SESSION['PRE']= $_SESSION['APLICA']."/presentacion";
$_SESSION['PER']= $_SESSION['APLICA']."/persistencia";
Forma de invocarlo desde el index.php
require_once ($_SERVER[DOCUMENT_ROOT]."/aplicacion/configuracion.php");
// Forma de usarlo
require_once($_SESSION['PRE'].'/class.Template.php');
Alternativa usando constantes (evitando las
sesiones)
define('HOME',$_SERVER[DOCUMENT_ROOT]);
define('APLICA',HOME."/aplicacion");
define('DOM',APLICA."/dominio");
define('PRE',APLICA."/presentacion");
define('PER',APLICA."/persistencia");
Forma de invocarlo desde el index.php
// No cambia
require_once ($_SERVER[DOCUMENT_ROOT]."/aplicacion/configuracion.php");
// Forma de usarlo
require_once(PRE.'/class.Template.php');
Conclusión final
Es una gran ventaja haber conocido otras plataformas, lo que te permite
tener un punto de vista más objetivo. Muchas veces creemos que no se puede
hacer o que está mal porque nuestro conocimiento y experiencia es muy
limitado.
Si no hubiera sabido como se hacía en otras plataformas
nunca me hubiera dado cuenta que me estaba faltando algo.
Espero que los programadores que nunca han visto programación "OO" y menos
una separación en 3 capas les despierte la curiosidad.
Lo lamentable de todo este
"parche" es que en la versión
6 este tipo de problemas debería estar resuelto simplemente como en
el siguiente ejemplo en Java:
En Java se usa la palabra "package", en
.Net la palabra "namespace", y en PHP6 (siguiendo la filosofía de copiar
todo de Java) se usará .... "namespace".