SimpleXML … la verdad es que sí

Tags: , , ,

Últimamente trabajo mucho con PHP y de vez en cuando toca lidiar con información de terceros en XML o HTML. Con las funciones (o métodos) de SimpleXML el trabajo es sencillísimo.

SimpleXML carga un archivo XML en memoria como una estructura similar a un array. A los atributos de una etiqueta se accede con la notación de array asociativo y al contenido de un nodo con la notación ->

Ejemplo:

<libros>
<libro id="1">
<titulo>El señor de los anillos</titulo>
<autor>Tolkien</autor>
</libro>
<libro id="2">
<titulo>El fin de la infancia</titulo>
<autor>Clark</autor>
</libro>
</libros>

Parsear este XML es trivial:

<?php
$libros = simplexml_load_file(‘libros.xml’);
foreach ($libros->libro as $libro) {
    echo sprintf(“Libro nº %s: Título: %s Autor: %s”,
            (string)$libro[‘id’],
            (string)$libro->titulo,
            (string)$libro->autor);
}
?>

El forzar la conversión de cada valor a string no es superfluo: si no se hace esto lo que obtenemos es otro objeto SimpleXML anidado al “padre” en vez del contenido del atributo o del nodo.

Otro uso posible es el parseo de HTML. Para garantizarnos que el HTML de origen está bien formado, conviene pasarle antes un tidy:

tidy -asxhtml -clean -numeric fichero.html
Comentarios

Patrones de diseño para torpes - 3ª parte

Tags: , , , , , , , , ,

El patrón “Singleton”

Uno de los patrones de diseño más conocidos es el patrón “Singleton“. Con este patrón se garantiza que sólo hay una instancia activa de una determinada clase.

Supongamos que tenemos una base de datos y queremos mantener una única conexión activa. Otro caso puede ser una clase que se dedique a grabar registros o trazas en un fichero. Imaginemos un objeto que descarga ficheros por FTP.

En todos estos casos puede ser conveniente tener un único objeto que realice el trabajo y garantizar que no hay varias instancias, por ejemplo, para no saturar una base de datos con conexiones, o no tener accesos simultáneos al mismo fichero, etc.

En la documentación oficial de PHP se muestra un ejemplo de este patrón para este lenguaje.

Otros patrones de diseño

Por motivos profesionales, últimamente casi programo exclusivamente con PHP. En developerWorks hay un artículo muy interesante donde amplían otro artículo anterior en el que presentaban cinco patrones básicos.

Explican y ponen ejemplos en PHP para los patrones “Adapter”, “Iterator”, “Decorator”, “Delegate” y “State”. Es una lectura obligatoria para cualquier desarrollador de PHP.

Comentarios

Patrones de diseño para torpes - 2ª parte

Tags: , , , ,

Seguimos la serie de artículos sobre patrones de diseño. Vamos a ver otro de los patrones más típicos.

El patrón “Observer”

Usted es el/la encargado/a de la hemeroteca de un laboratorio. Periódicamente se reciben revistas sobre diferentes temas y con una periodicidad variable: unas son semanales, otras quincenales y otras mensuales.

Una de sus funciones es hacer llegar las revistas a diferentes personas de diferentes departamentos. Por ejemplo, la revista “Genómica de las hormigas” debe llegar al laboratorio de genética, la revista “Cristalografía de minerales venusianos” va al departamento de cristalografía, etc.

Imagínese ahora que cada persona de cada departamento estuviese cada dos por tres llamándole para preguntarle si ha llegado su revista, o, peor aún, entrara en su despacho y revolviese su mesa y el archivo buscando su preciada revista.

Obviamente, las personas no trabajamos así, en este ejemplo, lo más lógico, cómodo y organizado es que Ud. mantenga una lista de las personas o departamentos y notifique a estos la llegada de las revistas. Cada departamento decide entonces qué hacer con la revista (fotocopiarla, escanearla, …, incluso leerla)

Cuando desarrollamos programas hay distintos módulos o unidades funcionales que deben interaccionar entre ellos, pero esta interacción no siempre es tan limpia o aséptica como sería deseable. En ocasiones un módulo, clase, función (o lo que sea) llega a “meterse en el despacho” de otra unidad funcional.

Pongamos un ejemplo más “software”. En el libro “Desing Patterns” que mencionábamos en el anterior artículo proponen dos ejemplos muy ilustrativos:

  • Una hoja de cálculo puede tener varias vistas (formas de presentar los datos) activas en un momento dado: un gráfico de barras, una rejilla de datos, un gráfico por sectores, …
    Si los datos cambian, todas las vistas deben actualizarse. La forma más cómoda es tener un objeto “Datos” que informa a todos los objetos “Presentación” de los cambios que se producen. Estos objetos “Presentación” ya se ocuparán ellos de actualizarse.
    Lo bueno de este patrón es que los objetos “Presentación” no deben “meterse en el despacho” del objeto “Datos” para consultar si estos datos han cambiado o no.
  • El otro ejemplo que se propone es un reloj. Tenemos un objeto “Temporizador” que cada segundo notifica a todos los objetos que le observan (un “RelojDigital”, un “RelojAnalógico”, …) de que algo ha cambiado.

Distinguimos entonces el objeto observado y los objetos observadores. El objeto observado debe mantener una relación de los objetos que le observan y una forma de notificarles. Por su parte, los objetos observadores, sean del tipo que sean, deben implementar alguna funcionalidad para actualizarse en función del nuevo estado del objeto observado.

En el artículo “Five common PHP design patterns” nos proponen algunos ejemplos en PHP muy interesantes. Vamos a adaptar un poco el ejemplo correspondiente al patrón observer y “traducirlo”.

<?php

interface IntfzObservador {
   function hayCambios($observado, $datos);
}

class NotificadorUsuarios implements IntfzObservador {
    public function hayCambios($sender, $args) {
        // Código para notificar: mensaje en consola,
        // registro en un fichero 'log', etc.
        echo("Se ha añadido '$args' a la lista de usuarios.n");
    }
}

class GrabadorBBDDUsuarios implements IntfzObservador {
   public function hayCambios($sender, $args) {
       // Código para grabar en BBDD.
       echo("Se ha grabado el usuario '$args' en la base de datos.n");
   }
}

class AltaSistemaUsuarios implements IntfzObservador {
   public function hayCambios($sender, $args) {
       // Código para crear la cuenta de usuario.
       echo("Se ha creado una cuenta para el usuario '$args'.n");
   }
}

class ListaUsuarios {
    private $observadores = array();
    public function anadirUsuario($nombre)  {
       foreach($this->observadores as $obs)
           $obs->hayCambios($this, $nombre);
    }
    public function anadirObservador($observador)  {
	    $this->observadores[]= $observador;
   }
}

/** Código de pruebas **/
$nu = new NotificadorUsuarios();
$gbu = new GrabadorBBDDUsuarios();
$asu = new AltaSistemaUsuarios();
$lu = new ListaUsuarios();
$lu->anadirObservador($nu);
$lu->anadirObservador($gbu);
$lu->anadirObservador($asu);
$lu->anadirUsuario("Juana");
$lu->anadirUsuario("Pedro");

?>

Las clases observadoras, independientemente de su naturaleza, deben tener un método común para ser notificadas por el observado. Esto puede garantizarse definiendo una interfaz (IntfzObservador en el ejemplo) y forzando a que estas clases observadoras implementen la interfaz.

El código es autoexplicativo. Tenemos dos observadores que “reaccionan” de diferente forma a los cambios en el observado. Uno de ellos de dedica a notificar los usuarios nuevos, otro los graba en una base de datos, otro los da de alta en el sistema, …

Cada vez que se añade el objeto ListaUsuarios añade un usuario, notifica a sus observadores y éstos hacen sus tareas, sin interferir con este objeto observado.

Veamos la salida de este programa:

~ $ php test.php
Se ha añadido ‘Juana’ a la lista de usuarios.
Se ha grabado el usuario ‘Juana’ en la base de datos.
Se ha creado una cuenta para el usuario ‘Juana’.
Se ha añadido ‘Pedro’ a la lista de usuarios.
Se ha grabado el usuario ‘Pedro’ en la base de datos.
Se ha creado una cuenta para el usuario ‘Pedro’.
~ $

Comentarios

Comparativa de “Frameworks” para PHP

Tags: , ,

Volvemos con la palabreja de moda: framework. Tras el enorme éxito de Ruby On Rails y otros framework como Trails, Django o TurboGears, el mundillo PHP se ha puesto las pilas y han surgido algunos proyectos similares.

¿Por qué utilizar PHP como lenguaje base para un framework en vez de otros lenguajes con una orientación a objetos más definida o clara como Ruby, Python o Java? [1]

La razón principal, en muchos casos, es la amplia extensión de PHP en los servidores. Prácticamente todos los proveedores suministran planes de hosting con PHP y MySQL. Si no se dispone de un servidor dedicado o especializado, no es habitual poder contar con Ruby, Java o Python para hacer desarrollos.

En mi opinión, los frameworks para PHP con más aceptación son el Zend Framework, CakePHP y Symfony. Mi impresión es que Zend Framework es, sobre todo, una colección de clases, paquetes y herramientas, mientras que CakePHP y Symfony son más del estilo RoR.

Entre CakePHP y Symfony se puede decir que el primero es más sencillo y que el segundo ofrece más características. Sinceramente, la mejor forma de evaluarlos es dedicando unas horas a cada uno, pero no siempre tenemos tiempo para esto. Afortunadamente, he encontrado dos comparativas (en inglés) muy ilustrativas:

[1] PHP 5 ha mejorado mucho en lo que a programación orientada a objetos se refiere. Ya tenemos control de acceso en los métodos, gestión de excepciones, …

Comentarios

Depurar PHP con Eclipse

Tags: , , ,

Curioseando un rato ya encontré la forma de depurar PHP con Eclipse. Eso de saber por dónde va el código a base de sentencias echo y var_dump no es muy serio.

La empresa Zend proporciona un “plugin” basado en PDT que incorpora un producto llamado “Zend Debugger”. En el momento de escribir ésto la versión “estable” de PDT es la 0.7, si bien existe una versión 1.0 que sólo funciona con Eclipse 3.3. El plugin que proporciona Zend se basa en PDT 1.0, pero funciona con Eclipse 3.2.

La instalación es muy fácil, en la página de Zend se describe. Sobre una instalación de Eclipse sólo hay que irse al “Update Manager”, poner la URL de Zend (http://downloads.zend.com/pdt) y listo.

Al grano. Veamos cómo se depura.

Tenemos un script muy sencillo (hola.php):

<?
$uno = "Hola, ";
$dos = "mundo";
echo $uno . $dos . "!";
?>

Veamos cómo se depura. Creamos un “PHP Project” y un archivo “PHP file”.

Haciendo doble click en el margen del editor de código se añade un punto de interrupción.

Añadir punto de interrupción

Con el botón derecho, damos al menú “Debug as PHP Script”. Se nos cambia a la perspectiva de PHP Debug y empieza la fiesta: podemos examinar y modificar el contenido de variables, poner más puntos de interrupción, saltar funciones, lo típico en un depurador.

Ejecución interrumpida a voluntad Ejecución interrumpida a voluntad

Lo que todavía no he conseguido es depurar las peticiones enviadas por el navegador (”Debug as PHP Web Page”). Estamos en ello ;-)

Comentarios (2)

      artículos anteriores ->