• Feed RSS
Estoy viendo muy seguido en foros que frecuento regularmente a muchos programadores que quieren dar "el gran salto" y evolucionar desde la programación estructurada hacia la programación orientada a objetos. El error más común que percibo es la falta completa de conceptos base, seguida de una pobre lectura de ejemplos sintácticos que no ayudan a comprender cómo verdaderamente se usan los objetos y cómo hacer para interactuar con ellos.

Estoy fervientemente convencido que enseñar conceptos de POO sin ayuda de UML es elegir el camino más empinado para el novicio. Cuando de abstracciones se trata, el cerebro trabaja mejor jugando con "imágenes", creando simples representaciones de lo que llamamos objetos y sus relaciones (tema que trataremos en otro artículo).

Bueno, no perdamos más tiempo y solucionemos esta carencia en 6 pasos concretos ;-)


Introducción: Representación de una clase

Una clase se representa con un "rectángulo" dividido en 3 zonas horizontales:
  • La primer zona se utiliza para colocar el nombre de la clase. Por convención los nombres de las clases inician con la primera letra en mayúsculas, y todas en singular (Persona, Cliente, Vendedor, Perro, Fruta, etc)
  • La segunda zona se utiliza para colocar la lista de atributos. Cada atributo iniciará con un símbolo que representará la "visibilidad" del mismo, que podrá ser "público" (+), "privado" (-) o "reservado" (#).
  • La tercer zona se utiliza para colocar los métodos de la clase. Cada método, igual que sucede con los atributos, deberá tener los mismos símbolos de "visibilidad" que se aplican con los atributos.
Se dice que la "zona de atributos" representa el estado actual del objeto (que cambiará según los valores que pueda tener en un momento dado) y la "zona de métodos" el comportamiento del mismo (dice qué puede hacer, qué se puede cambiar del mismo, qué se le puede preguntar, etc), configurando una suerte de "interfaz" que permitirá que otros objetos puedan interactuar con él (los objetos interactúan con otros objetos a través de sus métodos).

En este ejemplo podemos observar además que para cada atributo o método deberemos definir cual será el tipo de valor que manejará (String, Date, Integer, etc), no importando verdaderamente si nuestro lenguaje lo soporta en un 100%.

No hay que olvidar que UML es un lenguaje de modelado que permite comprender los diseños sin tener que llegar a conocer el código, y la traducción no está atada a ningún lenguaje de programación. Si el lenguaje es OO, se puede traducir, y tal vez, algunos detalles menores queden por el camino, pero que no debería afectar al concepto general de lo que se quiere transmitir.

Por ejemplo, PHP es un lenguaje de "tipado dinámico" (o lo opuesto a decir "tipado fuerte") donde según la asignación de valores (o su contexto de uso) define el tipo de la variable. Para el caso de la traducción del UML, cada vez que veamos el "tipo", este dato nos servirá como documentación sobre qué información manejaremos internamente, pero no se traducirá en código explícito (porque el lenguaje no lo provee).

Nota: por eso muchos critican a PHP en general. Al no tener un "tipado fuerte" no lo consideran un lenguaje orientado a objetos "robusto" (al existir menos controles sobre los valores que manejan las variables). Según el autor de PHP, esto es una ventaja del lenguaje -la flexibilidad- y juega en favor de los programadores, no en contra.

Paso 1) "Nombre del archivo"

Normalmente usamos un nombre seguido de la extensión: prueba.php. En el caso de los objetos, hay muchas opiniones al respecto. La mayoría de los autores sugiere diferenciar un archivo que define una clase de un archivo que usa varias clases predefinidas.

He visto autores que usan la siguiente nomenclatura: class.NombreDeLaClase.php.

En mi caso, yo siempre me sentí más cómodo usando NombreDeLaClase.class.php y así sigo manteniendo la estrategia de no alejarme mucho de Java para contar con un modelo de referencia para poder aprender de él.

La única ventaja que encuentro en la primera opción es que si listamos todos los archivos de un directorio, todos los que empiecen con "class." estarán juntos.

Para seguir el ejemplo, mi ejemplo, usaremos: Persona.class.php

Paso 2) "Definir la clase"

Aquí debemos ceñirnos a la sintaxis del lenguaje de turno al cual queremos convertir desde un diagrama UML. En nuestro caso, es PHP5, por lo cual solo debemos ir hasta el manual, buscar la parte donde hablan de creación de clases y hacer la siguiente conversión mecánica.

Nota: si usamos Eclipse como IDE para desarrollar, al momento de decirle "crear nuevo archivo php" y colocarle de nombre ".class.php", nos arma un esqueleto más completo de forma totalmente automática ;-)

Paso 3) "Definir los atributos"

Si ya tenemos el esqueleto principal, solo debemos leer uno a uno los atributos del UML y pasarlos a código casi de forma directa:
Como comentaba, no tenemos que preocuparnos de no disponer de un "tipado fuerte" (como sucede con Java) que nos obligue a escribir en la definición de atributos de que tipo son.
Podemos aplicar algunas "sutilezas" pero que en realidad no aportan mucho valor:

private $nombre="";

Con esta asignación estamos diciendo que el atributo es de tipo String.

En este caso, y para PHP, el tipado en el UML nos aporta información extra para la documentación de nuestro sistema (por lo cual no hay que obviarla a la hora de diseñar, aunque nuestro lenguaje no lo soporte explícitamente).

Paso 4) "Definir los métodos"

Siguiendo el mismo razonamiento que el usado en el caso anterior con los atributos, los métodos deben definir también su visibilidad:

Paso 5) "Definir un constructor"

Generalmente, aunque esto es flexible, en un diagrama UML que representa una clase no hace falta agregar como método el propio constructor de la clase; en sí, se sobreentiende que constará de uno y no aportaría nada nuevo a la documentación del diseño (de la misma forma que sucedería con los métodos "getter" y "setter", que hablaremos en otro artículo).

Como los atributos son "privados" (no se tiene acceso a los mismos desde fuera de la clase) para poder asignarles valores iniciales en el momento justo de la creación, deberemos crear un método constructor:

Recibimos los 3 parámetros desde el constructor y luego los asignamos a los atributos de la clase.

Este método se ejecuta "automáticamente" cuando hacemos un "new" para crear una instancia a partir de la clase (que se ve en el próximo paso).

Paso 6) "Probarlo"

Creamos la clase, usando el constructor, para luego usar un método del objeto.


Este ejemplo, en realidad, no imprimirá la edad del "vendedor", puesto que para simplificar el ejemplo y no agregar "ruido" al código (¡si habré visto libros con códigos innecesariamente complejos!), no está implementada la fórmula para calcular la edad a partir de la fecha de nacimiento ingresada (pero creo que la idea general se entiende).


Resumen final

Fuimos viendo paso a paso como se traduce a PHP5 la representación en UML de una clase definida en el contexto de la programación orientada a objetos. Conocimos las 3 zonas que definen una clase (nombre, atributos y métodos), la visibilidad (métodos y atributos), el constructor (para definir un comportamiento al crear el objeto) y finalmente, como probar la clase creada.

¿Dudas o sugerencias? Bienvenidas en los comentarios de este artículo ;-)

Artículo basado en una respuesta que di en Foros del Web

Actualización (27/07/2006): las capturas de pantallas están hechas sobre las siguientes herramientas: la versión "comunitaria" (gratuita) de Poseidon (basado en el proyecto libre ArgoUML) y Eclipse (usando el paquete EasyEclipse for PHP).
Muchas veces me han hecho esta pregunta, y muchas veces la he leído en foros de discusión, lo cual escribir repetidamente la respuesta se me hace un poco cansador.

En los próximos artículos voy a ir documentando estos casos, así cuando me lo vuelvan a preguntar, los remito aquí ;-)

En la programación por capas siempre debemos separar nuestro sistema en más de una "capa", donde por un lado tendremos una capa con la responsabilidad de implementar la "lógica" de nuestro sistema, y separar en otras capas las demás responsabilidades: capa de persistencia, de presentación (también llamada "interfaz" o "gui"), etc.

Capa de Lógica

A la capa de lógica también se le puede conocer con distintos nombres ("lógica de negocios", "dominio del problema", etc) y no necesariamente es una, puede estar compuesta por varias con distintos niveles de complejidad dentro (es decir, una capa que internamente tiene varias capas). Aquí es donde verdaderamente resolvemos el problema concreto, separado de los demás detalles que conforman nuestro sistema (que serían las otras capas, o las otras responsabilidades).

"Bajo Acoplamiento" versus "Reacción en Cadena"

Conceptualmente, lo único que debemos hacer es tener "separada" las responsabilidades en fuentes distintos, o en conjuntos de fuentes distintos (dependiendo el tamaño de nuestro sistema). Es decir, un conjunto de fuentes solo trabajarán la parte de la "lógica" donde tendrán prohibido hacer algo de la "presentación", y viceversa. Cada uno tendrá un punto de contacto que podrán ser datos pasados por parámetros, un objeto parámetro, una capa de "fachada", etc.

Aplicar cualquier estrategia que nos evite que nuestros subsistemas (o capas) estén "altamente acoplados", evitando que cada uno conozca detalles internos del otro para que cuando uno cambie no sea afectado en cadena la integridad de nuestro sistema, situación que nos obligará a modificar muchos fuentes para solucionarlo.

Un ejemplo práctico

En la capa de lógica tengo los fuentes que crean un resumen de cuenta de un cliente; arma la información necesaria a partir de los datos que fueron solicitados oportunamente a la capa de persistencia, para luego de terminada la tarea, cederle la responsabilidad a la capa de presentación para que -a partir de los datos ya procesados- armar una pantalla con columnas y colores, ubicando los datos donde corresponden.

La lógica no debe desplegar nada en pantalla ni tener acceso directo a la base de datos.

Su punto de contacto con los datos debe ser una clase que representará a la capa correspondiente a la cual le pedimos los datos con la mínima cantidad de información posible. No tendría sentido tener nuestro sistema separado en capas y que la lógica envíe sentencias SQL, lo que significaría que nuestra capa conoce demasiados detalles internos de otra capa, rompiendo el encapsulamiento. De la misma forma, tendríamos otra clase que representará a la "capa de presentación" que se encargará de recibir los datos y que nuestra "lógica" se desentenderá posteriormente (ya no será su responsabilidad).

¿PHP lo soporta?

Se puede hacer perfectamente con PHP, pero el tema es más simple de lo que parece: no debemos tener todo entreverado en los mismos fuentes, debemos ser ordenados y metódicos, separar cada objeto según su responsabilidad, y colocarlos en "contenedores" distintos.

Una forma de hacerlo es a través de herramientas, como Smarty, que permite trabajar separadamente tu código (la lógica) del código html (la presentación), donde dispondremos de un lenguaje propio para resolver problemas de la interfaz, facilitando la separación de capas.

Otra forma de hacer es con las propias "herramientas" que nos debería proveer el lenguaje (como sucede con Java o .Net), que nos facilitaría enormemente la administración y uso de las capas, tema tratado oportunamente en otro artículo en este blog.

Artículo basado en una respuesta que di en Foros del Web
"Smarty es uno de los templates engine (y tal vez un poco más allá) más populares entre los programadores que usan PHP. En somewhere in … colourful moments , publicaron un cheat sheet (hoja de referencia rápida) orientada a diseñadores de plantillas, que pueden encontrar bastante útil: Smarty cheat sheet for template designers."

Más información:
En SentidoWeb comentan que la empresa Zend (los creadores de PHP) han escrito 15 tutoriales dentinados a principiantes, para lograr crear una buena base de conocimientos. En lo personal, los voy a leer uno por uno (siempre te llevas la sorpresa al encontrar algo que no sabías, o por lo menos, no recordabas).

SentidoWeb se tomó el trabajo de armar una lista más descriptiva con comentarios de cada uno de los tutoriales:
  • Fundamentos de PHP: crear un 'Hola Mundo', comentarios, variables, tipos, ... Lo más básico y necesario de PHP.
  • Parámetros de entrada y condicionales : cómo se reciben los datos que nos llegan desde la URL y el uso de comparaciones e instrucciones condicionales.
  • Bucles y más condiciones: Bucles (for, while, ...) y cómo comprobar si una variable está definida.
  • Arrays: tratamiento de arrays, incluyendo el foreach.
  • Ficheros: abrir, leer, escribir en ficheros.
  • Funciones: uso de funciones, sus parámetros de entrada y variables globales.
  • Clases : todo lo necesario para la programación orientada a objetos mediante PHP.
  • MYSQL : acceso a base de datos MYSQL, imprescindible si quieres realizar alguna aplicación web.
  • SQLite: otra base de datos.
  • Sesiones: tratamiento de sesiones y coockies.
  • XML: tratamiento de XML, solo para PHP5, en PHP4 también se pueden tratar.
  • Tratamiento de errores : si vas a realizar una aplicación, gasta bastante tiempo en el tratamiento de errores, algo para mí fundamental.
  • Principios de seguridad: validación de los campos de entrada, sobre todo para cuestiones de BD.
  • Nuestra primera aplicación web: una vez conocido todo lo anterior, ya estamos preparados para hacer nuestra primera aplicación web.
  • Agregador RSS: creación de un pequeño agregador RSS.
Ya tengo la respuesta rápida para la próxima vez que me pregunten "que debo leer para empezar a programar en PHP" ;-)

Enlace original: PHP Tutorials for Absolute Beginners
Escribí una respuesta a un comentario de un lector del blog y esta se me volvió casi un "post" completo. Para que no quede en el olvido, lo muevo aquí, pues es algo que me han preguntado mucho y que he sugerido mucho sin que me preguntaran ;-)

Todo se inició hablando de componentes de Pear que ofrecen los servicios de "abstracción de Bases de datos", que entre otras cosas nos evitan que usemos  funciones específicas de PHP que nos atan a la base de datos de turno.

Marconi me consulta si no es mejor MDB2, lo cual le respondo lo siguiente:

Lo de "mejor o no", es dependiente siempre del contexto ;-)

No he tenido el gusto de probar todas las alternativas existentes en Pear, como el caso de MDB2, pero si te puedo hacer una sugerencia:

Crea un "capa de abstracción" que te "abstraiga" de las herramientas que ofrecen los servicios de "abstracción de bases de datos concretos" ;-)

Es decir, crea una clase BaseDeDatos (o como quieras que se llame) que use internamente, por ejemplo, MDB2. Deberás implementar por lo menos las operaciones básicas (conectar, desconectar, consultar, registros afectados, etc) ... pero no lo haces de cero, internamente lo haces con MDB2.

Si en un futuro, cercano o lejano, encuentras otra herramienta de abstracción que se adapta maś a tu contexto (rendimiento, flexibilidad, simplicidad, etc), podrás reemplazar MDB2 por la nueva, sin que tu aplicación se vea afectada por el cambio (ella dependerá de tu clase "BaseDeDatos", y no concretamente de una herramienta específica).

Una premisa en Diseño Orientado a Objetos es: "no dependas de implementaciones concretas, solo de implementaciones abstractas".

Veo muy seguido que los "novatos" (los que hacen sus primeras armas) lo primero que intentan es crearse componentes "de cero" (como la capa de abstracción) sin usar herramientas que los auxilien.

Reutiliza, no reinventes la rueda constantemente.

Pierde tiempo en las cosas que interesan, las que aportan "valor agregado" a tus desarrollos y a tus clientes.

"Interesante estudio sobre comparativa de sentencias en PHP5 que obtienen el mismo resultado, para conocer cual de ellas es la más rápida. Por ejemplo: es más rápido concatenar una cadena a una variable usando el punto (.) que incluyéndo la variable entre comillas dobles, para expresiones regulares es más rápido usar preg_match que eregi, es 8 veces más rápido usar explode que split. También es una buena referencia para saber como hacer lo mismo de distintas formas. Pero lo que más me ha sorprendido es que comparando con PHP4 las expresiones regulares se han vuelto más lentas (casi 7 veces más rápido en PHP4 que en PHP5), lo cual me hace pensar que o bien es debido a una mejora que completa las expresiones regulares, o antes no se hacían muy bien, porque ir a peor no tiene mucho sentido."


Artículo completo en: SentidoWeb

En un principio creé este blog, PHP Cinco, a mediados de agosto de 2005 para hablar de la nueva versión de PHP, concretamente la "5". El cambio de versión propiciaba toda una "revolución", pero no todos los programadores fueron conscientes de las nuevas puertas que se nos abrieron para potenciar nuestros desarrollos. De golpe, dimos un salto que nos permite acercarmos a niveles de programación similares al que se consigue con el famoso lenguaje Java. Este fue un primer importante paso que permitirá a PHP dejar de ser solo un lenguaje a convertirse en una plataforma de desarrollo.

En este caso tuve poca visión, o por lo menos, una visión muy a corto plazo. No se me ocurrió mejor idea que registrar el blog como phpcinco.blogspot.com y así lo llamé por unas semanas. Con el tiempo, creé varios otros blogs sobre temas que si bien se tratan en entornos PHP (como Pear y Smarty), seguí con la idea de que cada blog tuviera una temática muy concreta y especializada. El tiempo y la experiencia sirvió para decantar y pulir la estrategia: voy a unir los blogs sobre Smarty, Pear y PHP, en un nuevo nombre más genérico (que hace un tiempo ya estaba usando como "nombre fantasía" del blog): PHP Senior

En los blogs originales voy a hacer referencia en un último "post" que ahora nos encontramos en "PHP Senior" y voy a terminar de migrar los contenidos.

Si tenemos que hablar de Smarty o Pear, o de PHP5 (o el futuro PHP6), o del nuevo framework o el futuro RAD, lo haremos todo desde "PHP Senior".

¡Los espero, no se pierdan! ;-)

"Dentro de las librerías PEAR se está desarrollando una nueva forma de distribuir aplicaciones desarrolladas en PHP.
De la misma forma que java permite distribuir las aplicaciones en un solo archivo .jar, ahora en php podremos hacerlo con .PHAR"

Algunos links:

Fuente:
Este tema lo comenté por primera vez cuando escribí sobre cómo se representaría una arquitectura de 3 capas en PHP5. Ahora me entero que era más grave de lo que yo pensaba ;-)

Noticia extraida de VivaPHP:
"Petición para soporte de Name Spaces en PHP5 (07.04.2006)

PHP¿Hasta dónde pueden llegar los programadores de PHP en su súplica para que los desarrolladores de Zend vean la luz y agreguen de una soporte de name spaces a este lenguaje? Pues hasta el punto de organizar una petición on-line para implorar que por lo menos incluyan el parche de Jessie Hernandez en la próxima versión de PHP5.

El soporte de name spaces está en seria consideración para PHP6, con una álgida discusión en la lista de correo de php-internals sobre la mejor forma de implementar esta retrasadísima característica."

Antes que saliera la versión final de PHP5 leí la documentación sobre lo nuevo que incorporaba y se hacía referencia constante al concepto de "namespace". Al principio me sorprendió porque PHP5 se basa mucho en la sintaxis que usa Java para implementar los objetos y este usa la sintaxis "package" y solo en .Net se usaba "namespace".

La mayor sorpresa fue que cuando se liberó la versión final de PHP5, este no soportaba los "namespaces" (a pesar de haberlos probado en la beta).

Volviendo al tema, para ubicarnos un poco en el contexto, este tipo de sintaxis nos permite representar el concepto de diseño llamado "arquitectura en capas" o directamente "programación en tres capas" (pueden haber muchas más capas, pero generalmente se habla de que deberían existir por lo menos tres), donde deberíamos separar claramente las distintas responsabilidades básicas de nuestros sistemas.

La primer capa, la presentación, sería la encargada de manejar nuestra "interfaz" con los usuarios (pantallas gráficas, páginas web, etc), la segunda capa, el dominio o lógica, donde deberemos alojar el código que resuelve concretamente la problemática de nuestro sistema, y por último la tercer capa, la persistencia, que tendrá la responsabilidad de "persistir" la información, tanto almacenarla en una base de datos o en un archivo de texto (o en cualquier otro medio), para luego poder recuperarla cuando lo requiera nuestro sistema.

La idea de la "arquitectura orientada a capas" es que tenemos separadas de forma clara las responsabilidades, desacoplando nuestro código.

Si no tuviéramos capas, que es lo mismo que decir que tenemos una sola capa, nuestro código tendría entreveradas todas las responsabilidades. Cualquier cambio que se quiera hacer al código que implementa la interfaz afectaría a todo el resto del código. Si necesitáramos cambiar de interfaz (pasar de un sistema de escritorio de ventanas a un sistema web) deberíamos modificar todas las llamadas en nuestro código que cumplen esa tarea. Pero si tenemos "capas", podemos crear un nuevo "paquete" y sustituirlo por el anterior, y nuestro sistema debería poder seguir funcionando sin problemas. Sería exactamente el mismo caso si tuviéramos que cambiar de motor de bases de datos, solo deberíamos poder cambiar de "capa" y nuestro sistema seguir operativo (o por lo menos, las modificaciones solo afectarían un paquete, no al resto).

En UML cada capa representa un "paquete" (o viceversa), y estos contienen en su interior clases u otros paquetes, y en muchos lenguajes (como Java) esto se traduce físicamente en un directorio.

La idea es que si nuestro Gerente nos entrega el diagrama UML, nosotros deberíamos poder interpretar el diagrama y representarlo en código en alguno de los lenguajes disponibles que cumplan con la Orientación a Objetos.

La desventaja que tiene PHP, al no soportar los namespace, es que no podemos cumplir fielmente los diagramas UML al tener que incluir individualmente los archivos que vamos necesitando, cuando deberíamos poder hacer referencia directa a un "paquete" como una "unidad".

No es lo mismo decir en nuestro código:

namespace dominio;
namespace persistencia;

Que tener que hacer referencia a cada uno de los archivos que vamos a utilizar de nuestro "paquete":

require_once 'persistencia/BaseDeDatos.class.php';
require_once 'dominio/Clientes.class.php';
require_once 'dominio/Acreedores.class.php';
require_once 'dominio/Factura.class.php';
require_once 'dominio/LineaFactura.class.php';


Lo más grave de todo es que nos debilita el diseño al no permitirnos cumplir con lo básico de los "principios del diseño orientado a objetos". Nosotros deberíamos reusar "paquetes" y no partes concretas de esos paquetes (en este caso, serían las clases).

Esperemos que se implemente en PHP6 y demos un nuevo gran paso.
Gran dilema les voy a plantear. Acompáñenme al esotérico mundo del Diseño Orientado a Objetos ;-)

Supongamos que tenemos un sistema que hará las funciones de "máquina de escribir", donde obtendrá información a través de un dispositivo de entrada y luego enviará esta información a un dispositivo de salida.

Nuestro diseño estará compuesto por dos paquetes (en el contexto UML) que nos ofrecen los siguientes servicios:

Lógica: donde tendremos la implementación de "alto nivel" de nuestro problema (donde se manipularán los dispositivos).

Dispositivos: donde la implementación de nuestro paquete de "lógica" tendrá acceso a servicios de "bajo nivel" provisto por este paquete.


Entrando en el diseño interno de los paquetes, tendremos:

- Dentro del paquete "Dispositivos": las clases "Teclado", que retornará información en formato de texto, e "Impresora", que en algún momento recibirá un texto para ser impreso.

- Dentro del paquete "Lógica": la clase "MaquinaDeEscribir", que se encargará de crear las instancias correspondientes a los dispositivos de entrada/salida, y pasar la información que devuelve una clase a otra clase.

Imprementación

Seguiremos textualmente los diagramas UML para hacer la codificación de nuestras clases. Empezaremos con los dispositivos.

Archivo: Teclado.php

class Teclado
{
public function leer()
{
// a efectos del ejemplo, solo retornará un
// un texto como representación de una
// entrada de datos
return "texto ingresado";
}
}


Archivo: Impresora.php

class Impresora
{
function escribir($texto)
{
echo $texto;
}
}


Archivo: MaquinaDeEscribir.php


require_once 'dispositivos/Teclado.php';
require_once 'dispositivos/Impresora.php';

abstract class MaquinaDeEscribir
{
static function run()
{
$miTeclado = new Teclado();
$miImpresora = new Impresora();

$miImpresora->escribir($miTeclado->leer());
}
}

¿Cómo se prueba?

Una posible solución creativa, tratando de llevar a PHP hacia un lenguaje 100% Orientado a Objetos (como Java), donde *todo* debería ser un objeto, se usará el "index.php" como una clase "Index".

Nota1: siguiendo el comportamiento estándar de los servidores web, cuando nos posicionemos en la url de nuestro sitio el servidor buscará todos los documentos que inicien con el nombre "index" (minúsculas) y luego probará varias extensiones hasta dar con el archivo inicial (.html, .htm, .php, etc). Hay autores que usan "class.NombreClase.php" o NombreClase.class.php, nosotros usaremos el estádar definido por Zend (NombreClase.php) y para este caso particular simplemente "index.php".

Resumiendo: Solo en este caso, para mantener el estándar web, nuestro archivo se llamará "index.php" y la clase internamente será "Index" (la primer letra en mayúsculas y la palabra en singular).

Nota2: cuando en un diagrama UML tenemos una flecha que apunta hacia otra clase (cualquier flecha), en PHP se traduce *siempre* (o por lo menos hasta la fecha de hoy) en incluir ese fuente con la sentencia include, require, etc. En el caso siguiente, y basado en nuestro diagrama UML, nuestra clase "Index" requerirá *solo* de la clase "MaquinaDeEscribir".

Nota3: como no hace falta instanciar la clase para invocar un método, creo una clase "abstracta" y ejecuto directamente la clase e invoco su método, evitando crear una instancia (menos código, no reservo memoria para la instancia, etc).


require_once "logica/MaquinaDeEscribir.php";

abstract class Index
{
static public function run()
{
echo 'Ejecuto máquina de escribir->';
MaquinaDeEscribir::run();
}
}

Index::run();

Ok, nuestro ejemplo está funcionando.

Ahora la pregunta es: ¿existe alguna otra mejor forma de hacerlo?

Programación Orientada a la Interface

Por suerte sí, existe otra forma: usando interfaces. Para poder aplicar esta nueva forma de solucionar el problema, debemos "dar vuelta" la forma que usamos los objetos de nuestro ejemplo. En el caso anterior, la clase de "alto nivel" dependía de dos clases de "bajo nivel", lo que significa algo muy grave: "la clase de alto nivel es *dependiente* de los cambios que puedan sucederle a las clases de bajo nivel, es decir, nuestro alto nivel depende de los detalles de implementación del bajo nivel".

El problema de nuestro diseño es que estamos programando "orientado a la implementación".

¿El diseño anterior, puede considerarse un buen diseño?

  • ¿Cuan mantenible será nuestro sistema si elementos de bajo nivel pueden generar cambios en todo el modelo?
  • ¿Es correcto que nuestra MaquinaDeEscribir dependa de cómo se toman los datos y de cómo se imprimen?
  • ¿Qué es lo más importante en nuestro diseño? ¿la Lógica o los Dispositivos?
  • ¿Este diseño, es reutilizable? ¿podemos reutilizar el MaquinaDeEscribir en otros contextos?
  • ¿Su costo de mantenimiento es alto o bajo? ¿cuanto código hay que agregar para extender su comportamiento (para cubrir un nuevo requerimiento)?
  • ¿el código presentado se mantiene, o hay que adaptarlo cada vez que queramos extender su funcionamiento?

Todas estas preguntas serán desveladas en el próximo capítulo ;-)
Luego de muchos preparativos se abre en la Universidad ORT el período de inscripción para el curso que dictaré sobre "Programación PHP5" en el marco del "Ciclo de Especialización dirigido a profesionales de Sistemas y Electrónica".

Por las características del temario del curso, este el primero y el único del mercado que contempla los últimos avances en la programación web con el lenguaje de programación PHP en su versión 5.

Cualquier duda o consulta, pueden enviarme un correo que ampliaré toda la información que soliciten.

El detalle completo se encuentra en el Blog de Enrique Place
La intención general de muchos patrones es contener el "foco de cambio", el lugar donde podrían originarse cambios en nuestro sistema, lo que requeriría tener que modificar código del mismo. Si "controlamos" ese foco, lograremos cumplir el principio "Open/Closed" (Abierto/Cerrado) que dice que: "nuestros sistemas deberían ser cerrados al cambio pero abiertos a la extensión". En otras palabras, nuestro diseño debería proveer la posibilidad de que nuestro sistema pueda crecer agregando nuevo código sin alterar el código existente.

Cuando nos acostumbremos a implementar patrones, nos daremos cuenta que la mayoría de los diseños cumplen con este principio.

En el caso concreto del patrón "Template Method", su intención es controlar el esqueleto de un algoritmo, permitiendo ofrecer un comportamiento base que pueda ser modificado al redefinir los métodos en las clases derivadas de la "Clase Padre" en el contexto de la herencia.

El gran beneficio de este patrón es la flexibilidad para aplicar cambios y para reusar código, facilitando además la alteración del "algoritmo base" de la solución que estamos implementando. El algoritmo está implementado en un único método y si debemos modificarlo este cambio impactará en todo el sistema de forma controlada, sin tener que modificar individualmente a las clases concretas (donde se encuentra la implementación de bajo nivel). Y sobre el caso de reuso, la "clase padre" de la herencia puede contener un "comportamiento por defecto" que todas las "clases hijas" van a heredar, y solo sobreescribirán el método correspondiente cuando necesiten cambiar su comportamiento según nuestros requerimientos.

Contexto del ejemplo

Necesitamos una estructura que nos permita generar listados que cumplen el siguiente algoritmo: imprimir primero la información del cabezal, luego el cuerpo y finalmente el pie del documento. Cada clase derivada vuelve a implementar el método que hereda de la "clase padre" cada vez que necesite cambiar el comportamiento base. De la misma forma, si deseamos agregar un nuevo tipo de listado, no necesitaremos modificar el código de nuestra solución, solo crear una clase y heredar de la clase padre ("abierto a la extensión").

Por demás está decir que el "foco de cambio" es claro: si tenemos un sistema que provee listados de distinto tipo, es muy probable que con el tiempo surjan modificaciones en el comportamiento general (cambia la estructura o el diseño de nuestra hoja de impresión) o se agregan nuevos casos a los existentes (un nuevo tipo de listado).

Se creó una clase Listado que será la única estructura que contendrá verdaderamente el algoritmo de la solución (dentro del método imprimir) y una serie de métodos que pertenecen *solo* a la lógica interna del algoritmo.


// Archivo: Listado.class.php

class Listado {

// Algoritmo base
public function imprimir(){
$this->cabezal();
$this->cuerpo();
$this->pie();
}
// Contenido inicial para cada parte del
// algoritmo

protected function cabezal(){
echo
"Listado - Cabezal";
}
protected function cuerpo(){
echo
"Listado - Cuerpo";
}
protected function pie(){
echo
"Listado - Pie";
}
}
?>

// Archivo: Comun.class.php

require_once 'Listado.class.php';

class
Comun extends Listado{

// Altero el comportamiento base
// de una parte del algoritmo, el "pié"

protected function pie(){
echo
"Comun - pie";
}

}
?>

// Archivo: Avanzado.class.php

require_once 'Listado.class.php';

class
Avanzado extends Listado{

// En este caso, modifico completamente
// el contenido de los elementos que
// comprenden el algoritmo, pero no
// quiere decir que pueda cambiar
// el orden del mismo (esto se mantiene
// controlado en la clase base "Listado")

protected function cabezal(){
echo
"Avanzado - cabezal";
}
protected function cuerpo(){
echo
"Avanzado - cuerpo";
}
protected function pie(){
echo
"Avanzado - pie";
}
}

?>

// Archivo: Estandar.class.php

require_once 'Listado.class.php';

class
Estandar extends Listado {
// En este caso, no hacemos nada
// y se reaprovecha todo el contenido
// de la "clase base"
}
?>

// Archivo: index.php

require_once 'Listado.class.php';
require_once
'Comun.class.php';
require_once
'Avanzado.class.php';
require_once
'Estandar.class.php';

abstract class Index {
public static function run(){
self::imprimir(new Comun());

self::imprimir(new Avanzado());

self::imprimir(new Estandar());
}
// Solo pueden pasar como parámetros
// objetos que sean del tipo "clase base",
// logrando efectuar un "contrato de diseño"
// (para poder imprimir debes heredar de la
// clase "Listado").
private static function imprimir(Listado $b){
$b->imprimir();
}
}

Index::run();
?>



Detalles a tener en cuenta

La definición del diseño del patrón dice que los métodos que se utilizan son parte del algoritmo y están con la visibilidad "protegida" y no "privada". Si fuera así, los métodos no podrían ser accesibles desde otras clase de la jerarquía, impidiendo que puedan sobreescribirse.

Si fuera "públicos" los métodos, podrían ser accedidos directamente desde la clase "cliente" (en este caso "Index") y acceder a partes del algoritmo, lo cual solo nos interesa que lo ejecuten de forma integra. Para este último caso está disponible el método "imprimir" de la clase "Listado".

Y como último detalle, no hace falta instanciar clases que no se necesitan o no deban hacerlo ... para eso se define clases "abstractas" que impiden la creación de instancias y a los métodos como "estáticos", lo que impide que puedan ser usados en el contexto de una instancia.

Dudas, sugerencias, correcciones, insultos, en los comentarios, plis ;-)

Más información

Wikipedia

Do Factory
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.

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" X-)))

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 he llegado a hacer (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. Cuantos habrán dicho a Colón que estaba loco y que la Tierra no podía ser redonda ;-)

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:

Mi estimado colega, el mexicano Carlos Madrigal ha liberado un Podcast sobre PHP5. Los invito a escucharlo y a disfrutar del programa.

De la misma forma, aunque nuestros intereses pasen solo por temas como PHP o Software Libre, la mayoría de los podcast son muy didácticos, y cual más cómico y divertido (yo mismo me he encontrado escuchando programas por solo el hecho de escuchar las ocurrencias de Carlos ;-)

Podcast: PHP5

PD: tarde, pero lo publiqué.
En EstadoBeta, comentan el polémico artículo escrito por el autor de PHP:

"Rasmus Lerdorf, creador de PHP, publicó el Lunes recién pasado una nota donde recomienda no usar frameworks de desarrollo y, en general, tender hacia un estilo procedural de programación - o sea evitar el uso de clases y objetos o “desarrollo en capas”, algo por desgracia frecuente en el mundo PHP-.

Estas recomendaciones parecen contravenir la tendencia actual hacia un desarrollo más estructurado y sostenible, representado por un sinnúmero de frameworks de desarrollo y una reconsideración de los lenguajes “de scripting” como PHP, Python o Ruby en el mundo “Enterprise” (donde por lo general han primado metodologías más estrictas y estructuradas como J2EE o .NET).

El artículo es especialmente desconcertante viniendo del creador del lenguaje, especialmente con el advenimiento de PHP5 y 6 que han centrado sus esfuerzos en mejorar el modelo de objetos para competir abiertamente con Java y .NET (y ahora Ruby!).

Los comentarios alarmados no se hicieron esperar en el sitio. Incluyendo los mios."


Y esta es mi opinión al respecto:

Sorprende, pero no tiene que alarmarnos, la evolución del lenguaje no depende de una sola persona y de su visión personal. A pesar que el autor piensa de esta forma, PHP5 ha evolucionado hacia un nivel similar al J2SE (Java2 Standard Edition), y están tratando de llegar con PHP6 y el Framework de Zend al nivel de J2EE (Java 2 Enterprise Edition).

¿Qué significa?

Las empresas, el mercado, y en particular, los desarrolladores, están dictando el camino.

Estoy de acuerdo que el nivel general de los desarrolladores de PHP están aún en la programación estructurada, un número importante se ha pasado a un “híbrido” (estructurado con uso de objetos), una minoría a un uso “puro” (enteramente Orientado a Objetos) y muy contados casos, cuentan con el conocimiento de los Patrones de Diseño (y generalmente, son programadores que vienen del mundo J2EE, donde es muy común su uso).

De todas formas, creo que existe una explicación racional. Muchos sitios web no superan la complejidad básica de mostrar muchas páginas estáticas y un 10% de dinamismo, que se puede resolver rápidamente con pocas funciones estructuradas.

El problema es:
  • ¿podremos avanzar al próximo nivel cuando nuestros desarrollos cambien y se necesite sitios más complejos?
  • ¿podremos desarrollarlos programando “estructurado”, o peor aún, como si fueran simples scripts?
  • ¿seremos productivos?
  • ¿podremos mantenerlos?
  • ¿a que costo?

La programación “OO” no es una simple moda; no hay lenguaje o tecnología que no haga uso de ella.

Enlaces
"El lenguaje PHP cumplió 10 años en 2005 y promete seguir expandiendo su territorio en 2006 gracias al próximo lanzamiento de su versión 6.

En cuanto al lanzamiento de la versión 6 -que se producirá en algún momento de 2006- los expertos afirman que una de sus principales ventajas será la utilización de UNICODE. Este sistema provee una manejo universal de los caracteres, sin depender de ninguna plataforma en particular.

Por otra parte, en enero de 2006 se publicarán las primeras bases del “PHP Collaboration framework”, una iniciativa para crear un nuevo entorno de implementación y desarrollo para PHP. Se espera que esta iniciativa pueda acercar a PHP al ámbito corporativo para competir de igual a igual con otras plataformas como .NET y Java.

De esta manera, a partir de 2006 coexistirán en el mercado tres versiones distintas de PHP: la 4, la 5, y la 6."


Noticia completa en:
NoticiasDot.com
Caso: levantamos un campo de texto de nuestra base de datos que tiene un formato con retornos de carro, es decir, tiene escritos tres párrafos separados con un [Enter].


Si nosotros tomamos ese campo, tal cual, y lo incluimos en nuestra plantilla html, nuestro texto quedará todo junto sin saltos.

Si visualizamos el código que estamos viendo desde nuestro navegador, el texto aparecerá con los "saltos de carro" correctos.


¿Por qué sucede esto?

Bueno, en HTML solo se toma en cuenta *un solo espacio*, los restantes no son tenidos en cuenta, ni tampoco los comandos que representan "retorno de carro" (\n) o los tabuladores (\t), etcétera.

¿Cómo podemos solucionarlo con Smarty?


Una expresión regular que toma el contenido "en bruto" y busca los comandos "\n" y los sustituye con un "salto de línea" en formato HTML.


{$elemento.texto_noticia|regex_replace:"/[\n]/":"
"}

Resultado: si tiene un solo "retorno" (\n) se coloca un "break", si tiene dos, agrega dos "break", dando el efecto de separación con linea en blanco.


De la misma forma, podríamos hacer con los "\t", y agregándoles, por ejemplo, una serie de espacios en formato html:

Simple, sencillo, directo ;-)

PD: estoy casi seguro que esta "estrategia" está escrita en algún lado, tal vez en el manual del Smarty, o en un artículo (porque vino demasiado rápido a mi cerebro ;-).
En este pequeño post nos cuenta como se puede armar una estructura que permita crear sitios que manejen varios idiomas, o por lo menos, tener una versión que soporte más de un idioma.

Fuente: Buayacorp
"Y después del explosivo éxito que el año pasado tuvo Rails como framework para el desarrollo web, todo el mundo PHP quiere llevar esa misma magia al lenguaje más popular en los servidores de Internet. Desde la mismísima Zend para abajo, todos quieren ser el próximo Rails. Pero ¿es ésta una tarea en la que PHP puede triunfar?"


Artículo completo en: VivaPHP
Es muy común que cuando cambiamos de año, como en este caso de 2005 a 2006, lo primero que queda desactualizado son los mensajes de "Copyright". En estos casos se manejan formatos del tipo:

Copyright 1995-2005 - República de los Jedis

Donde se maneja un rango de años, desde el inicio del sitio hasta la fecha actual.

Nota: ni idea si esta "formalidad" tiene algún peso legal, y si está basado en alguna norma, o simplemente nos fuimos copiando unos a otros hasta que se hizo "estándar".

Que sucede: en los sitios estáticos (es decir, su contenido solo cambiará si es modificado a mano) la fecha actual deberá ser actualizada, cambiando el año 2005 por el 2006.

Lo peor que podría pasar es que el sitio no fuera "modular", es decir, que cada página de nuestro sitio no tuviera "ciertos contenidos" centralizados que al modificar en un único lugar impacten en todo el sitio web.

Por ejemplo, este es un caso. Si nuestro sitio es completamente estático y cuenta con 50 páginas, deberemos recorrer y modificar el año de Copyright de las 50. Si, verdaderamente grave si para algo tan sencillo, debemos hacer tanto trabajo.

En mi caso, esta zona la considero como el "pie" del sitio, como así
también existe el "cabezal", y se encuentra en un solo archivo que es
incluido por todas las páginas del sitio. Editamos el archivo, cambiamos el año a 2006, y problema solucionado.

A pesar de todo, me queda el "retrogusto amargo" de que el año que viene tendré el mismo problema ;-), por lo consiguiente llegué a la conclusión que el último año es una información dinámica que debe darla el sistema: "el año actual"

Código original






Que podemos cambiar la línea siguiente por:

Copyright 1995- - República de los Jedis



Si, di una introducción larga para darle un poco más de sentido a tan poco código ;-)

Enlaces relacionados:
¡Suertempila!
"Molins es un framework orientado a objetos para PHP5 (que cumple rigurosamente el modo E_STRICT), basado en el estándar de Java y alguno de los proyectos de Jakarta, como lo son Struts o Torque.

Aún no alcanzando una versión estable, pero en su corta edad, ya cuenta con soporte casi completo para el modelo MVC de Struts, así como también herramientas para hacer logging, un 'package' gráfico, seguridad, etc. Está realizado por un grupo de desarrolladores de Barcelona y espera ansioso vuestras opiniones."


Fuente: programacion.com
Cito el siguiente artículo traducido por la gente de MilDiez:
"Traduzco libremente este post en LaughingMeme: 20 pequeños consejos que deberíamos tener en cuenta antes de escribir una biblioteca de funciones en PHP.

Muchos de estos consejos pueden ser aplicados al desarrollo web en general y están enfocados a maximizar algunos de los principios básicos de la programación: ocultación de la información, abstracción, reutilización y encapsulación".
Artículo completo: Consejos para escribir bibliotecas en PHP
"Framework basado en Ruby on Rails que transa muchas de las ventajas de la OOP con tal de ser extremádamente fácil de usar."

Artículo completo en: EstadoBeta
"El nuevo corazón de PHP, Zend Engine 2, incorpora un nuevo modelo de objetos, mucho más cercano a lenguajes totalmente orientados a objetos como Java.

Este artículo recoge y analiza algunas de las características más destacadas."


Artículo completo en: Epsilon Eridani
"En 1995 Rasmus Lerdorf quería saber cuántas personas estaban leyendo el curriculum vitae en su página web y para ello creo un CGI en Perl que mostraba el resultado estadístico en la propia página. Rasmus llamó a ese script PHP, acrónimo de Personal Home Page. Inmediatamente comenzó a recibir pedidos de muchas personas para obtener el pequeño programa y Rasmus lo compartió con ellas y creó una lista de correo para intercambiar opiniones, sugerencias y correcciones. Como resultado de todo esto, Rasmus accedió a un puesto en la Universidad de Toronto para crear un sistema administrado por web para que los estudiantes se conecten a Internet, mediante acceso discado, con control de cuentas de acceso en base horaria y reflejando todos los datos en tiempo real sobre una base de datos ..."

Continúa leyendo su biografía en Wikipedia
"En PHP no existen los punteros, pero al ser un lenguaje interpretado es sencillo ofrecer funcionalidades similares. Disponemos de dos opciones, una la más simple, basada en llamar a funciones o métodos a partir de una variable string que contenga el nombre de la función o método, lo cual se denomina en PHP funciones variables, y otra, basada en la utilización de algunas funciones específicas de PHP, que nos ofrecen algo más de potencia que el caso anterior ..."

Artículo completo en: Es Lo Mas
Estuve revisando los artículos que tengo guardados en mi cuenta de Gmail (me auto envío correos y tengo filtros para ir ordenándolos en "Etiquetas") y para que sean de provecho para otros desarrolladores (pues leo y descarto todos los días artículos y manuales) publicaré progresivamente enlaces que considero útiles y de buena calidad:

Nota: aunque no todos hablan exclusivamente sobre PHP5, se aplican sin problemas a todas las versiones, incluyendo la última.

Para este ejemplo vamos a asumir que estamos usando el motor de base de datos MySQL y una base de datos "prueba", donde crearemos un formulario para solicitar el id del cliente y luego consultar la base de datos para recuperar la información del mismo.

Debemos crear la tabla "clientes" que contendrá los siguientes campos: id y nombre.

Este es el código de nuestro "formulario.php":


require_once "HTML/Form.php";
$form = new HTML_Form('consulta.php');
$form->addText("id", "Número de cliente?");
$form->addSubmit("submit", "Consultar");
$form->display();
?>


Creamos nuestro primer formulario usando la clase "HTML_Form", donde en el constructor de la clase definimos cual será el programa que se encargará de procesar la información del formulario y hacer la consulta SQL (consulta.php). Creamos un campo para recibir el número de id (método addText) y el botón de "Consultar" (método addSubmit).

require_once 'DB.php';
$db =& DB::connect('mysql://root:@localhost/prueba');
if (PEAR::isError($db)) {
die($db->getMessage());
}

$db->setFetchMode(DB_FETCHMODE _ASSOC);
$sql = "SELECT * FROM clientes";
if($_GET['id']<>""){
$sql .= " WHERE id='".$_GET['id']."'";
}
$res =& $db->query($sql);

while ($res->fetchInto($row)) {
print_r($row);
}
?>

En el archivo "consulta.php" recibimos el valor cargado en el formulario ($_GET['id']) y si este tiene un valor (es distinto de cero) se crea una sentencia SQL para obtener el cliente, de lo contrario traerá todos los clientes.

Simple, directo y sencillo. Con el framework Pear pudimos armar la parte de la "presentación" (el formulario) y parte de la "persistencia" (con el resultado).
El problema

El template Smarty puede tener algunas dificultades a la hora de instalarlo:
  • No tenemos control del servidor donde alojamos nuestro sitio, solo de un directorio.
  • No tenemos conocimientos suficientes para configurar el servidor web.
  • Hemos seguido el tutorial de la página oficial pero tuvimos problemas al entenderlo o simplemente no pudimos seguir los pasos.
  • Estamos en Windows usando algún software que nos provee el entorno de desarrollo (Apache, PHP, MySQL, etc) pero no Smarty, y el tutorial de instalación no contempla este contexto.
  • etcétera.
Introducción

El template Smarty, al final de cuentas, es un conjunto reducido de clases que ofrecen la funcionalidad de "templates html" para nuestros desarrollos basados en PHP, donde terminamos usando una instancia (POO) para manipular la información y el comportamiento del motor de templates.

Una solución fácil y rápida

Bajar el paquete Smarty y descomprimirlo en el directorio donde se encuentra nuestro sitio web. Si no tenemos acceso a la línea de comandos en el servidor, lo bajamos en nuestro equipo de desarrollo, descomprimimos el paquete, y luego subimos el directorio entero a nuestro sitio.

Por ejemplo

Si el directorio en el servidor web es "/var/www/" y el directorio de nuestro sitio es "misitiopersonal", la ruta completa sería "/var/www/misitiopersonal".

Si nos bajamos el paquete de Smarty del sitio oficial, este vendrá comprimido y la nomenclatura del mismo será: "Smarty-2.6.10", donde la información que precede al guión hace referencia a la versión del mismo.

Tips: si queremos simplificar la instalación, configuración y uso del template, podemos modificar el nombre del directorio (o crear un link) a uno abreviado. Por ejemplo: solo "Smarty".

Los directorios que necesitamos

Se necesitan por lo menos los siguientes directorios:
  • templates: este directorio contendrá los templates para nuestras páginas web, es decir, los archivos .html que contienen código html con la posibilidad de ser invocado desde un PHP.
  • templates_c: es el directorio temporal donde el sistema lee los templates del directorio anterior y genera un nuevo html de forma dinámica con el código resuelto, es decir, código html y la sustitución de todas las variables cargadas y las sentencias propias resultas por el Smarty. Este resultado es la "página final", lo que recibirá el usuario cuando navegue nuestro sitio web.
Luego, creamos el siguiente archivo PHP para probar el template.



require_once("Smarty/libs/Smarty.class.php");

$miSmarty = new Smarty();

$miSmarty->template_dir = 'templates';
$miSmarty->config_dir = 'config';
$miSmarty->cache_dir = 'cache';
$miSmarty->compile_dir = 'templates_c';

$miSmarty->assign("titulo", "Formulario de Consultas");
$miSmarty->display("formulario.tpl.html");
?>

Incluimos la clase base "Smarty.class.php" y luego creamos la primer instancia de nuestro template, modificamos los atributos de la clase para definir donde estarán los directorios necesarios para su trabajo y creamos una variable del template (assign) y le cargamos el título del formulario ("Formulario de Consultas").

Finalmente, invocamos el template con el método "display".

Nuestro primer template

Podemos usar la nomenclatura que más nos guste; en este caso seguimos los ejemplos de la documentación oficial: nombredearchivo.tpl.html, donde "tpl" es la abreviación de template y obviamente "html" porque es un archivo con ese formato. Esto último es útil para poder editar el archivo en nuestro editor HTML de preferencia.

Deberemos tener creado el archivo "formulario.tpl.html" en el directorio "template" con el siguiente contenido:

{$titulo}

Donde el "{$titulo}" será sustituido con el contenido especificado en archivo PHP.

En Resumen

Logramos instalar Smarty sin depender de la configuración del servidor, sin necesitar tener acceso como administradores. Logramos modificar su comportamiento, creamos la primer instancia del objeto y logramos ejecutar el primer template.

Ahora que el entorno está pronto, tenemos el camino abierto para aprender a usarlo, solo queda leer el manual! ;-)

En próximos artículos abordaremos los temas iniciales de como empezar a usar el motor de templates Smarty.

¡Saludos!
Siguiendo en la línea del artículo anterior sobre el tema Patrones de Diseño, donde se trataba en particular el patrón "Factory Method" en PHP4", se implementará un ejemplo aprovechando las nuevas características que ofrece la versión 5 de PHP.

Descargos al respecto

Los "patrones de diseño" se representan con diagramas UML y son una guía para su implementación. No necesariamente se puede/debe implementar el patrón de la misma forma en todos los lenguajes, y nosotros además podemos modificarlos para adaptarlos a nuestras necesidades particulares.

Implementación

Se definen dos clases, "Conductor" y "Vehiculo", y una "Fábrica" de objetos que tendrá la responsabilidad de crear a demanda las instancias de esas clases.

class Conductor{

function
__toString() {

return
"Soy un Conductor";

}

}

class
Vehiculo{

function
__toString(){

return
"Soy un Vehiculo";

}

}

abstract class Fabrica {

public static function crear($tipo){

return new
$tipo();

}

}

Ejemplo de Uso
echo Fabrica::crear("Conductor");

echo
Fabrica::crear("Vehiculo");
En ambos casos usamos la "Fabrica" sin tener la necesidad de instanciarla, invocando directamente a la clase y usando el método "crear". La fábrica necesita recibir por parámetro el nombre de la clase del objeto que se desea crear, y ella nos devolverá una instancia de la clase solicitada.

Sobre el "toString"

Como las clases implementan los métodos "toString", cuando hacemos "echo" de la instancia recibida, el método es invocado automáticamente y nos devuelve la descripción del objeto.

El "toString" es un concepto muy usado en la POO: generalmente es un método reservado (como el constructor, el destructor, etc) y por definición es la forma estándar de convertir un objeto en String.

Resumen final

La ventaja de este "patrón de diseño" es que tenemos centralizada la creación de objetos en una entidad que a pedido nos devuelve instancias de los mismos. Es una forma de tener el control de la creación de objetos, y donde podemos agregar procedimientos para registrar cada creación y actuar en consecuencia (estadísticas, seguridad, etc).

¡Saludos, hasta el próximo patrón!