lunes, 29 de agosto de 2011

Annotations, esas desconocidas en PHP

He de reconocerlo, me encantan las annotations (attributes en .NET). Me parecen una de las herramientas mas útiles que nos puede proveer un lenguaje de programación y me pongo burro cuando las veo por algún sitio.

Ya me había acostumbrado a ellas en Java hace tiempo cuando comencé con Hibernate y más tarde seguí usándolas con .NET. Las annotations, en este caso, eran una manera de los más limpia para no tener que toquetear un xml cada vez que cambiaban los objetos de datos.

Creas tu objeto de datos y lo mapeas en dos patadas, tal que así:

@Entity
@Table( name = "EVENTS" )
public class Event {
   ...
}

Trabajo terminado.

Más o menos hace un año, mientras estaba RESTificando unga, que está programado, por ahora, con PHP, me surgieron una serie de dificultades:
- Necesitaba devolver los resultados en diferentes formatos (XML, JSON, HTML).
- PHP es un lenguaje de tipado débil y sólo en muy contadas ocasiones se puede especificar un tipo de datos.
- Con lo anterior tenía problemas para mapear números y cadenas, o incluso tipos de datos binarios sin mantener en algún sitio un objeto de conversión específico para cada tipo de datos. En Java/.NET/etc. es mucho más sencillo pues en cada momento se puede acceder al tipo de cada variable.

Cómo pasar, por ejemplo de ésto:

public class Cosa {
    public $DatoCadena = ‘pakito’;
    public $DatoFloat = 0.123;
    public $DatoEntero = 123;
    public $ArrayDeObjetos;
}

A ésto:

<?xml version="1.0" encoding="UTF-8" ?>
<Cosa>
    <DatoCadena>pakito</DatoCadena>
    <DatoFloat>0.123</DatoFloat>
    <DatoEntero>123</DatoEntero>

<ArrayDeObjetos>

    <Objeto....

    ...

</ArrayDeObjetos>
</Cosa>

O más difícil aún, ¿cómo hacerlo a la inversa? (de XML a objeto).

Recordemos: PHP es un lenguaje de tipado débil, de ahí el problema. Los Javeros, NETeros, C++eros y similares lo tienen algo más sencillo.

Hay muchas formas y podrían hacerse muchos tipos de parsers pero siempre vamos a encontrarnos con que esos parsers no van a ser genéricos y requerirán que, cada vez que se modifique una clase, se incluyan sus nuevas propiedades específicas (por ejemplo, DatoPatito, haciendo referencia a objetos de tipo Patito).

Podría delegarse la responsabilidad en cada objeto de datos, la cual fue mi primera opción, pero sería un coñazo, con el tiempo, tener que escribir las funciones de serializacion/deserialización cada vez que se crease un tipo de dato nuevo.

En mi afán de obtener grandes resultados con el mínimo esfuerzo se me ocurrió que quizás con annotations en PHP podría especificar el tipo de datos de cada propiedad y crear únicamente serializadores genéricos que no habrían de ser tocados cada vez que se crease una nueva clase.

La clase anterior bien podría quedar tal que así:

class Cosa {
    /* @type = ‘string’ */
    public $DatoCadena = ‘pakito’;
    /* @type = ‘float’ */
    public $DatoFloat = 0.123;
    /* @type = ‘integer’ */
    public $DatoEntero = 123;
    /* @type = ‘array’, @object_type=’Objeto’ */
    public $ArrayDeObjetos;
}

Limpio, claro y sin errores. Y además los componentes que tuviesen que tratar con esos objetos podrían tener especificados el tipo de datos con el que trabajarían y, si algún día hubiese que cambiarlo, sería modificar un simple parámetro. Por ejemplo:

/* @object_type = ‘Cosa’ */
public function HacerCosas {...}

Pues sí, aunque conozco a muchos desarrolladores que están en contra de estas cosas tan dinámicas, de construcción automática de código, de mapeos y de cosas así... no puedo evitarlo, a mí me gusta.

Si a la supuesta sobrecarga de la “interpretación” de PHP (medio desmentido aquí: http://www.phpclasses.org/blog/post/155-Top-10-Wrong-Ideas-About-PHP-That-You-Should-Get-Right.html ) le añades que antes ha de examinar (reflexión) las clases de datos y decodificarlas la aplicación se morirá de asco.

Yo no he notado disminución de rendimiento apreciable y sólo por la comodidad que me ofrece vale la pena la posible “pérdida” que pudiese acarrear. Hay que tener en cuenta que en los entornos de desarrollo yo no uso op-code caches ni optimizaciones de ningún tipo (memcache, caché de páginas, etc.).

Para “escoger” qué solución de Annotations era la más adecuada, en mi caso, me guié por las opciones presentadas aquí: declarative development using annotations in php. Al final me decidí por Addendum  porque no todos los hosting tienen la posibilidad de instalar PEAR y porque además podría modificarla a gusto si lo necesitase.

En unga todos los DTOs están “anotados” y me resulta muy sencillo realizar clases de serialización. Por ahora serializa para XML y JSON pero hay un futuro brillante esperando porque la era móvil me está obligando a pensarme ciertas cosas sobre la presentación.

Así que sí, PHP tiene Annotations. Y decían que no era un lenguaje serio...

Salut!

1 comentario:

Edu dijo...

Buenas,

Pues yo tampoco sabía que PHP tenía anotaciones :-/ A ver si vuelvo a probarlo. En la parte web me dijeron que symfony 2 (o como se escriba) está muy muy bien.

Sobre los de las automagias. A mi me gustan. Sobretodo las que no se ven :-P. Las herramientas de generación de código también me gustan. Lo que no me gusta mucho es que generan código con un estilo distinto del resto de la aplicación. Si el código que generan ya tiene warnings o directamente veo alguna mala práctica, ya comieno a sospechar. Si las tengo que usar, siempre creo un proyecto rollo biblioteca aparte.

De hecho ahora estoy flipándolo con Grails (2 años después) que básicamente lo que hace es endiñar muchisimo código en tiempo de ejecución.

El problema es cuando, no sabes muy bien como funciona lo que estás usando y de repente comienza a fallar. Por suerte existe stackoverflow :P