Programación Modular en PHP
IntroducciónLa mayoría de los que hemos trabajado alguna vez con PHP, nos hemos encontrado con que todo mundo lo considera un lenguaje altamente "modular". Incluso, muchos de los scripts existentes son completamente modulares.
Sin embargo, a pesar de todo esto la información sobre como crear software modular es mínima y muchas veces resulta difícil saber como empezar.
¿Que son los módulos?Podemos considerar un módulo, como una pieza de software que provee de funcionalidad a una aplicación. Por lo general, un módulo posee una serie de funciones internas (o interfaces), que le permiten comunicarse con la aplicación y viceversa.
Un software modular, es aquel en que todas sus partes funcionales están compuestas por "módulos" que podemos activar o desactivar en base a nuestras necesidades.
¿Como se puede crear un sistema modular?Lastimosamente, no existe un estándar que nos diga como programar un sistema modular. Sin embargo existe cierta términologia que nos puede ser útil para darnos una idea de como funciona todo esto.
Primero, consideremos a nuestro software, como un objeto.
[Software]Para que un sistema sea modular, es necesario que se comunique de alguna manera con los módulos, que son
otras piezas de software que proveen funcionalidad al sistema.
[Software]<====
interfase====>
[modulo]El problema principal es.. ¿Como sabe nuestro software la manera adecuada de comunicarse con nuestro módulo?
En algunos lenguajes de programación, es posible definir un tipo de objeto llamado Interfase. Una interfase actúa como plantilla estableciendo las funciones que una clase debe de tener, para que otro objeto o pieza de software se comunique con ella.
Imaginemos que tenemos una función en php que formatea texto en HTML.
<?php
echo formatear("texto","Negrita");
?>
La función formatear, toma el primer parámetro, y lo ajusta a la salida en base al valor del segundo parámetro.
Para nuestro caso, la sintaxis de la función es la siguiente:
function formatear(<texto a formatear>,<nombre modulo>);
Ahora debemos definir una interfase común, para todas nuestras clases que dan formato al texto. Lo haremos de la siguiente manera:
Archivo:
Formateador.interface.php<?php
interface Formateador {
function formatear($texto);
}
?>
Como podrán observar, en una interfase no definimos nada de código, sino simplemente la función que nuestro modulo deberá implementar para poder formatear un texto.
Ahora que tenemos nuestra interfase, podemos crear módulos diferentes:
Archivo:
Negrita.class.php<?php
class Negrita implements Formateador {
function formatear($texto) {
return "<strong>$texto</strong>";
}
}
?>
Archivo:
Cursiva.class.php<?php
class Cursiva implements Formateador {
function formatear($texto) {
return "<i>$texto</i>";
}
}
?>
Archivo:
Subrayado.class.php<?php
class Subrayado implements Formateador {
function formatear($texto) {
return "<u>$texto</u>";
}
}
?>
Notarán algo interesante en todos los archivos y es que el nombre del archivo PHP coincide con el nombre de la clase. Esto se hace de esta manera, ya que cargaremos todos los módulos siguiendo el siguiente algoritmo:
1-Obtener el nombre del modulo
2-Revisar si existe un archivo que coincida con el nombre del modulo
3-Crear un objeto con el nombre del módulo especificado
4-Llamar a la función formatear($texto) del modulo recien cargado
Antes de seguir, vamos a crear dos archivos más, para probar módulos con formatos inválidos:
Archivo:
Novalido.class.php<?php
class Novalido {
function formatear($texto) {
return $texto;
}
}
?>
Este archivo esta escrito correctamente, y posee la función de la interfaz, sin embargo, como no utilizamos "
implements", no debería ser considerado como un modulo válido.
Utilizar
implements nos asegura que la clase que cargaremos posee al menos los métodos especificados de la interfaz para poder comunicarnos con los módulos.
Archivo:
NoClase.class.php<?php
class otroNombre implements Formateador {
function formatear($texto) {
return $texto;
}
}
?>
Este archivo implementa la interfaz Formateador, pero la clase definida dentro de el no tiene el mismo nombre que el archivo, por lo tanto nos deberá de generar un error.
Por último creamos nuestra función formatear(<texto>,<nombreModulo>), que cargará de manera automática los modulos especificados:
Archivo:
index.php<?php
// Este archivo es importante ya que
// Define nuestra interface para comunicarnos
// con los modulos
include("Formateador.interface.php");
function formatear($texto,$modulo) {
// Revisamos si el modulo especificado
// existe
if(is_file($modulo.".class.php")) {
// Cargamos el archivo del modulo
require_once($modulo.".class.php");
// Revisamos que se pueda crear un
// objeto con el nombre de clase dado
if(!class_exists($modulo)) {
return "El archivo $modulo.class.php existe, pero no hay ninguna clase de nombre $modulo";
}
//Creamos una nueva instancia del modulo
$formateador = new $modulo();
// Revisamos si el modulo es una instancia
// de un Formateador
if($formateador instanceof Formateador) {
// Llamamos a la funcion de formateo de
// texto del modulo
return $formateador->formatear($texto);
} else {
return "El modulo $modulo, no es una instancia de Formateador";
}
} else {
return "El modulo no pudo ser cargado";
}
}
// Luego agregamos la página para hacer pruebas
?>
<html>
<head><title>Prueba de Módulos</title></head>
<body>
<p>Este es un archivo de prueba de modulos</p>
<p><?php echo formatear("Modulo Negrita","Negrita") ?></p>
<p><?php echo formatear("Modulo Cursiva","Cursiva") ?></p>
<p><?php echo formatear("Modulo Subrayado","Subrayado") ?></p>
<p><?php echo formatear("Modulo no existente","Dummy") ?></p>
<p><?php echo formatear("Modulo no valido","Novalido") ?></p>
<p><?php echo formatear("Modulo no valido","NoClase") ?></p>
</body>
</html>
La salida debería de ser similar a la siguiente:
Este es un archivo de prueba de modulos
Modulo Negrita
Modulo Cursiva
Modulo Subrayado
El modulo no pudo ser cargado
El modulo Novalido, no es una instancia de Formateador
El archivo NoClase.class.php existe, pero no hay ninguna clase de nombre NoClase
ConclusiónEl hecho de que PHP sea un lenguaje de script y que permita la inclusión dinámica de archivos, permite que crear sistemas modulares sea sumamente fácil.
En este ejemplo se trabajó cargando todos los archivos de manera local, creando una interfaz que sirve de plantilla para las funciones que se utilizaran por el programa.
Si se necesita de cargar una gran cantidad de módulos, se pueden guardar los nombres de los mismos en una base de datos y luego por medio de algún programa podemos indicar cuales archivos cargar y cuales no.
El implementar los módulos haciendo uso de interfaces facilita muchísimo el proceso de chequeo de funciones, permitiendo verificar si un módulo posee todas las funciones que llamaremos simplemente haciendo uso del operador "
instanceof".
.-
Espero este pequeñísimo artículo les haya sido de utilidad!!
P.D.: Pueden encontrar los archivos de este tutorial en el anexo Modulos.zip