Generador de aplicaciones de zenphp - Manual Versión: 0.0.1 RC 2 - Escrita: Enero/2008

Guilherme Blanco

Características nuevas de la versión

Listado de contenidos

  1. Introducción
  2. Empezando
    1. Instalación
    2. Tutorial sencillo
      1. Construyendo una clase PHP básica (la base)
      2. Creando código propio
      3. Cargando la clase básica
    3. Probando la instalación
    4. Troubleshooting
  3. ¿Qué es POA ?
    1. Introducción
    2. POA:: ¿Qué nombre utilizar?
      1. Aspecto (Aspect)
      2. Anotación (Advice)
      3. Punto de Unión (Join Point)
      4. Punto de corte (Pointcut)
      5. Tejedora (Weave)
  4. Guía completa
    1. Introducción
      1. Misión
      2. Convenciones
      3. ¿Cómo funciona ?
        1. Estructura interna
    2. XML de la definición de Aspectos(DAX)
      1. DTD para generar el XML de los Aspectos
      2. Definiendo Puntos de corte y Anotaciones
      3. Restricciones
    3. Código de clases PHP
      1. Puntos de corte de usuario
      2. Puntos de corte automáticos
    4. Cargando nuestra aplicación
      1. Cargando el fichero de la clase
      2. Configurar el compilador

1. Introducción

En pocas palabras,el generador de aplicaciones POA de zenphp es un conjunto de clases que funcionan conjuntamente para emular el paradigma de la Programación Orientada a Aspectos.
Soporta PHP 4.3.0+, la simplicidad es el objetivo del paradigma,todo es controlado por un fichero entendible a simple vista XML con definiciones de aspectos (XAD) o en español (DAX : Definiciones de Aspectos en XML).
El documento explica todos los recursos disponibles del paquete. Es una poderosa herramienta que se puede utilizar tanto como para generar aplicaciones como para utilizar scripts que se autocompilen.

2. Empezando

2.1. Instalación

Ya viene instalado, basta con estar en un directorio con permisos de escritura.

Demasiado difícil para ti? :)

2.2. Tutorial sencillo

En este capítulo construimos un pequeño y sencillo ejemplo para aprender los principos de la POA, suficiente para que los programadores entiendan las bases del paradigma y los mecanismos de generación sin problemas.
Primero creamos una clase sencilla que sirve de base,para adornarla con aspectos que se definen en un fichero XML. En la sección "Probando la instalación " se explica como se comprueba si todo ha funcionado correctamente y cómo se solucionan los problemas que hayan ocurrido.

2.2.1. Construyendo una clase PHP básica

Suponemos que nuestro Diagrama de Clases en UML es tal como éste: (ver directorio tutorial)

+-------------------------------+
| Prueba                        |
+-------------------------------+
| - mensaje: string             |
+-------------------------------+
| + Prueba(m: String): Prueba   |
| + ponerMensaje(m:string):void |
| + obtenerMensaje(): string    |
| + mostrar(): void             |
+-------------------------------+

Ahora, creamos el código o si usamos aplicaciones como Andromda nos genera el código automáticamente:

<?php
/**
*@example Clase Prueba de ejemplo para el generador del Paradigma de la Programación Orientada a Aspectos
*/
class Prueba {
	var $mensaje;

	function Prueba($m) {
		$this->ponerMensaje($m);
	}

	function ponerMensaje($m) {
		$this->mensaje = $m;
	}

	function obtenerMensaje() {
		return $this->mensaje;
	}
	
	function mostrar() {
		echo $this->mensaje;
	}      
}
?>

Guardamos el fichero en el directorio de la raíz de zenphp de forma que queda así web/tutorial/clase_Prueba.php ; web/tutorial/zenphp/...

2.2.2. Creando código Propio

Suponemos que necesitamos llevar un control de las llamadas a los métodos, por ejemplo: añadir un sistema de Depuración, ...entonces, consideramos que queremos incluir un Aspecto de depuración.
Para insertar código en las llamadas lo que hacemos es usar el nombre de la función y con "antes" o "después" definimos dónde colocar lo <nuevo>.

La Definición XML de Aspecto te permite escribir Código PHP (o cualquier otro código) para ser mezclado, es lo que se llama una Anotación (Advice).
Lo que hacemos es escribir unos cuantos trozos de código propio (nuestro) para ser incluido en la clase Prueba, gracias a la sintaxis de XML se puede usar una jerarquía muy simple donde el elemento raíz o root es un Aspecto y soporta uno o más Puntos de Corte (Pointcuts) que es donde se "coloca" el código. Cada punto de corte contiene unos atributos que definen la localización donde aplicaremos los cambios que vienen en los nodos CDATA (el código PHP nuevo).

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE aspecto SYSTEM "../zen_esquema_poa.dtd">

<aspecto>
    <punto_corte auto="despues" function="ponerMensaje" clase="Prueba">
    <![CDATA[
        echo "Fin de la funcion " . __FUNCTION__ ."(\"" . $m . "\") .<br />";
    ]]>
    </punto_corte>

    <punto_corte auto="despues" clase="Prueba" nombre_funcion="mostrar">
    <![CDATA[
        echo "Fin de la llamada de la funcion " . __FUNCTION__ ." .<br />";
    ]]>
    </punto_corte>

    <punto_corte auto="antes" nombre_funcion="mostrar" clase="Prueba">
    <![CDATA[
        echo "Principio de la llamada de la funcion " . __FUNCTION__ ." .<br />";
    ]]>
    </punto_corte>
    
    <punto_corte auto="vistazo" function="mostrar" clase="Prueba">
    <![CDATA[
        echo "<b>Mensaje: </b>";
        procesar();
        echo "<br />";
    ]]>
    </punto_corte>
</aspecto>

El primer punto_corte es un Punto de corte automático (detallado más adelante) específico para el método ponerMensaje. Su anotación imprime el nombre de la función y el contenido de la variable local $m.
El segundo punto de corte aplica la misma anotación (Advice) para todas las llamadas de la clase Prueba, al final de éstas, excepto el método "mostrar".
El tercer punto de corte es también automático y su anotación imprime un mensaje conteniendo el nombre de la función, y se aplica al principio de todos los métodos o funciones definidas del .PHP base,pero no se aplica a la función ni método llamado "mostrar". El último punto de corte ,otro automático, se aplica al método mostrar de la clase Prueba. Mostrará la primera línea después de los comandos del método, después mostrará la nueva línea de código HTML. Por lo tanto la función procesar(); quiere decir que es ¡el método completo!

Guarda el fichero XML como depurador.xml dentro de la carpeta donde colocaste la clase_Prueba.php ,el directorio tutorial . web/tutorial/depurador.xml

2.2.3. Cargando la clase básica

La última parte de este manual-manifiesto del generador zenphp::POA explica como aplicar el XML de aspectos a la clase original.

El motor POA de zenphp define varias funciones dependiendo de lo que necesites hacer con tu aplicación, existe una función llamada zen_crear_script que es del estilo is a require_once que compila el fichero de aspectos en una clase para cargarlas una vez hecho esto. Si el fichero compilado no existe, se compila y se intenta guardar en un fichero con un nombre único (se usa md5 para codificar el nombre). Para tareas más avanzadas se encuentra la función zen_crear_proyecto() , que ahora es utilizada por el script zenphp/generador/generar.php para crear aplicaciones de los proyectos con modelos,vistas,controladores y ayudantes.

NOTA: Comprueba que el directorio tutorial tiene permisos de escritura pues será necesario para poder guardar el fichero de la clase generada tras aplicar las reglas POA del depurador.xml.

El script que carga los ficheros es realmente nuestra aplicación xD . Con unas cuantas líneas de código se muestra como funciona la POA.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
/**
*@desc Clase Prueba de ejemplo para el generador del Paradigma de la Programación Orientada a Aspectos
*/
require_once "../zenphp/generador/zen_libreria_POA.php";

// Cargar clase compilada o compilar y guardar
zen_crear_proyecto("clase_Prueba.php", "depurador.xml");


// Probando
$prueba = new Prueba("juaxix");

if ($prueba->obtenerMensaje() != "Autor") {
    $prueba->ponerMensaje("jbelon");

}

$prueba->mostrar();

?>

Guarda el fichero como index.php dentro de /web/tutorial/index.php

Ejecuta index.php en tu servidor y verás como se van ejecutando todas las anotaciones,justo como se han definido.

2.3. Probando la instalación

El código generador , si ha funcionado todo correctamente, debería parecerse a lo siguiente:

<?php
/**
*@example Clase Prueba de ejemplo para el generador del Paradigma de la Programación Orientada a Aspectos
*/
class Prueba {
	var $mensaje;

	function Prueba($m) {   
/* zenphp::generador "antes" Codigo Auto */ 
      echo "Principio de la llamada de la funcion " . __FUNCTION__ ." .<br />";
      echo "<b>Mensaje: </b>";       
$this
->ponerMensaje($m); /* zenphp::generador "despues" Codigo Auto */
echo "Fin de la funcion " . __FUNCTION__ ."(\"" . $m . "\") .<br />";
echo "Fin de la llamada de la funcion " . __FUNCTION__ ." .<br />";
echo "<br />";
} function ponerMensaje($m) {
/* zenphp::generador "antes" Codigo Auto */
echo "Principio de la llamada de la funcion " . __FUNCTION__ ." .<br />";
echo "<b>Mensaje: </b>";
$this->mensaje = $m;
/* zenphp::generador "despues" Codigo Auto */
echo "Fin de la funcion " . __FUNCTION__ ."(\"" . $m . "\") .<br />";
echo "Fin de la llamada de la funcion " . __FUNCTION__ ." .<br />";
echo "<br />";
}
function obtenerMensaje() {
/* zenphp::generador "antes" Codigo Auto */

echo
"Principio de la llamada de la funcion " . __FUNCTION__ ." .<br />";
echo "<b>Mensaje: </b>";
/* zenphp::generador "despues" Codigo Auto */
echo
"Fin de la funcion " . __FUNCTION__ ."(\"" . $m . "\") .<br />";
echo
"Fin de la llamada de la funcion " . __FUNCTION__ ." .<br />";
echo "<br />";
return
$this->mensaje; } function mostrar() {
/* zenphp::generador "antes" Codigo Auto */
echo "<b>Mensaje: </b>";
echo $this->mensaje;
/* zenphp::generador "despues" Codigo Auto */
echo "Fin de la funcion " . __FUNCTION__ ."(\"" . $m . "\") .<br />";
echo "<br />";
} }
?>

Next section explains commom mistakes. If the compiled file exist and if its code does not match with above code, notify me via email (guilhermeblanco [at] hotmail [dot] com), messenger (same as email) or at PHP Classes.org Forums.

2.4. Solución de errores

(Por escribir)

3. ¿Qué es POA?

Visitar: http://en.wikipedia.org/wiki/Aspect-oriented_programming.

3.1. Introducción

(Introducción)

3.2. POA :: ¿Qué nombres utilizar?

La teoría que la especifica define los nombres en inglés...

3.2.1. Aspecto / Aspect

Conjunto de Puntos de corte, perspectivas del sistema: depuración, muestro de datos,etc.

3.2.2. Anotación / Advice

Una anotación o Advice es un trozo de código. Se aplica a un Punto de unión

3.2.3. Punto de unión / Join Point

Lugar donde se coloca ,dentro del fichero original (punto de corte) donde se puede definir dónde se va a colocar el código nuevo.

3.2.4. Punto de corte / PointCut

Es el conjunto de anotaciones (Advices). Código aplicado en un Punto de unión (Join Point).

3.2.5. Tejedora (Weave)

Es el marco de trabajo del sistema. Más técincamente, donde el conjunto de Aspectos toman una forma concreta.

4. Guía completa

4.1. Introducción

4.1.1. Misión

(Explicar)

4.1.2. Convenciones

(Explicar)

4.1.3. ¿Cómo funciona?

La idea es muy simple.

          +-------------------+
          | Clase_Original.php|
          +-------------------+
                   /\
                   ||                      +---------------------+
                   ||=====================>| Clase_compilada.php |
                   ||                      +---------------------+
    +-----------+-------------------+
    |           |                   |
+-------+   +-------+           +-------+
|  DAX  |   |  DAX  |  .  .  .  |  DAX  |
+-------+   +-------+           +-------+

Con la clase original tenemos ficheros DAX (Definiciones de Aspectos en XML) que añaden y al final se guarda como la clase compilada.

4.1.3.1. Estructura interna

Lo simple es lo que funciona

(Explicar)

4.2. Definición de Aspectos en XML (DAX)

4.2.1. Definiciones base del XML : fichero de la estructura POA en formato DTD

(Ver fichero /zenphp/generador/zen_esquema_poa.dtd) ent.

4.2.2. Definiendo Puntos de Corte y Anotaciones

(Explicar)

4.2.3. Aplicando restricciones

(Valores en atributos)

auto="antes|despues|vistazo"

Es opcional, pero si no se establece, entonces el atributo "nombre" debe ser definido.
Si se incluye, entonces se ha de exponer en el Punto de Corte el códigode la anotación que se va a usar:

ATENCIÓN: "vistazo" es de gran utilidad pero hay que tener en cuennta ciertas consideraciones
Un nivel es cuando tienes varios bloques anidados, una sentencia if, while , try-catch, etc.
I will highlight one example:
function obtenerLinea() {
    if ($this->linea < 0) {
    	return 0;
    } // fin-if
	
    return $this->linea;
} // fin-metodo
Otro ejemplo:
<![CDATA[
    try {
        procesar();
    } catch ( Exception $e ) {
        die( $e->obtenerMensaje() );
    }
]]>
Cuando se compila,el problema se muestra:
        function obtenerLinea() {
            /* POA "antes" Codigo Auto */
            try {
                if ($this->line < 0) {

                /* POA "despues" Codigo Auto */
                } catch ( Exception $e ) {
                    die( $e->obtenerMensaje() );
                }

                return 0;
            } // fin-if
        } catch ( Exception $e ) {
            die( $e->obtenerMensaje() );
        }

    /* POA "despues" Codigo Auto */
    } catch ( Exception $e ) {
        die( $e->obtenerMensaje() );
    }

    return $this->linea;
} // fin-metodo
Como puedes ver ,la última llave está 2 niveles fuera de lo que debería estar. Se compila y se genera sin errores pero cuando,es cargado ,entonces devuelve un error fatal.

Remiendo no usar demasiados niveles dentro del "vistazo" de un punto de corte automático o no usar más de un nivel.
Estamos trabajando para solucionarlo :)
nombre="...[, ...]"

Especifica un Punto de corte propio del tipo <punto_corte nombre="MiPuntoDeUnion1, MiPuntoDeUnion2"...>...</punto_corte>

funcion="...[, ...]"

Atributo opcional para restringir el punto de corte a dicha función.

clase="...[, ...]"

Atributo opcional para restringir el punto de corte a dicha clase.

nombre_funcion="...[, ...]"

Atributo opcional para definir qué funciones no queremos que utilicen los puntos de corte, se aplican a todas las demás.

nombre_clase="...[, ...]"

Atributo opcional para definir qué clases no queremos que utilicen los puntos de corte, se aplican a todas las demás.

4.3. PHP Class Code

4.3.1. Puntos de Corte Propios

Los siguientes dos ejemplos son auto-explicativos :

<?php

class Prueba2 {
    ...

    function metodo($arg1, $arg2) {
        // tareas aqui
        ...
		
        /// punto_corte: miPuntoCorte
        ...
    }

    ...
}

?>
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE aspecto SYSTEM "zen_esquema_poa.dtd">

<aspecto>
    <punto_corte nombre="miPuntoCorte" clase="Prueba2">
    <![CDATA[
        echo "Hola mundo soy un Punto de Corte!!<br />";
    ]]>
    </punto_corte>
</aspecto>

4.3.2. Puntos de corte automáticos

(Introducción)

4.4. Cargando una aplicación

4.4.1. Cargar el fichero

(Explicar la llamada)

(colocar aquí la función)

 

4.4.2. Modificando las opciones de compilación

POA::CACHE("...");

Valor por defecto: Directorio por defecto del directorio de las clases . Para resetar, usar zen_POA::CACHE(".");
Las clases compiladas se generarán dentro del directorio especificado.

AOP::COMPACTAR(true|false);

Valor por defecto:false.
Si se cambia a "true", el código de la anotación (Advice) no será compactado, y las líneas de referencia entre la clase original y la compilada estarán formateadas de forma distinta.

AOP::RECOMPILAR(true|false);

Valor por defecto: false.
Para realizar construcciones "al vuelo".
Si se cambia a "true", cada vez que se ejecute el script ,se recompilará el fichero POA, incluso aunque sus ficheros (DAX y la clase original) no hayan cambiado.

NOTA: No es recomendable usarlo en la producción (por cuestiones de eficiencia).