Mostrando entradas con la etiqueta PHP5. Mostrar todas las entradas
Mostrando entradas con la etiqueta PHP5. Mostrar todas las entradas

viernes, 11 de junio de 2010

Devolver objetos en JSON desde PHP


Yo digo que es una dona

¡Saludos blogueros!

Ese pequeño artículo va para los que se preguntaban en el ejemplo anterior, ¿qué era ese formato llamado JSON que utiliza flickr para enviarnos la información? Se trata más que nada de una forma para intercambiar datos estructurados entre diferentes sistemas sobre protocolos como HTTP. JSON, define cómo se deberán codificar los objetos de un determinado lenguaje para convertirlos en cadenas de texto, con el propósito de enviarlos hacia otras aplicaciones, y que estas puedan reconstruirlos como objetos nativos, utilizando la decodificación definida por el mismo formato JSON.

Por ejemplo, digamos que mi aplicación desea mandar un objeto que contiene determinada información hacia un cliente Javascript, además de las ya conocidas técnicas basadas en XML o protocolos como SOAP, tenemos la posibilidad de mandarlo codificado en JSON, de modo que desde nuestra aplicación convertiremos ese objeto en una cadena de texto que lo representará, y lo enviaremos a nuestro cliente Javascript como una respuesta en texto simple, el cliente -con previo conocimiento del formato de la respuesta-, solo tendrá que aplicar las reglas de la notación para -partir de la cadena- reconstruir el objeto y utilizarlo dentro de su propia ejecución de instrucciones. Tal y como hicimos en el ejemplo anterior con los servicios de flickr.

La gran ventaja de JSON, es que el cliente Javascript puede utilizar la instrucción eval, para reconstruir el objeto partir de la cadena recibida, sin necesidad de ningún interprete especia, tal y como explica el artículo de la Wikipedia sobre JSON. Del lado de nuestra aplicación en el servidor por otro lado sí se necesitará de una funcionalidad que haga el trabajo de codificar los objetos u arreglos en la notación de JSON, pero para eso la gran mayoría de los lenguajes cuentan ya con bibliotecas de funciones o clases para hacer la tarea.

En este artículo veremos cómo hacer esa tarea del lado del servidor, utilizando la biblioteca de funciones para JSON de PHP, disponible a partir de la versión 5.2.0. Creando la siguiente aplicación web en este lenguaje:

respuestajson.php
<?php

//Clase para representar una serie de diferentes artículos para tiendas

class Articulo {
public $id;
public $nombre;
public $categoria;
public $precioDeSalida;
public $detalles;
}



$articulo = new Articulo();
$articulo->id = 1;
$articulo->nombre = "Nintendo DS";
$articulo->categoria = "Videojuego";
$articulo->precioDeSalida = "$3 500";
$articulo->detalles = array('Soporta juegos para Gameboy advance','Pantalla tactil','Reproducción de MP3');
echo json_encode($articulo);?>


El programa en PHP codificara en notación JSON el objeto $articulo, dando como resultado una cadena que devolverá al cliente, la cual podemos visualizar si accedemos a la aplicación desde el navegador (http://localhost/respuestajson.php):


{"id":1,"nombre":"Nintendo DS","categoria":"Videojuego","precioDeSalida":"$3 500","detalles":["Soporta juegos para Gameboy advance","Pantalla tactil","Reproducci\u00f3n de MP3"]}


Ahora, el cliente AJAX para procesar estos datos sería el siguiente:

clientejson.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Decodifica un objeto en JSON</title>
<script type="application/javascript">
var http_request = new XMLHttpRequest();
var url = "http://localhost/respuestajson.php"; // Esta URL debería devolver datos JSON

// Descarga los datos JSON del servidor.
http_request.onreadystatechange = manejaJSON;
http_request.open("GET", url, true);
http_request.send(null);

function manejaJSON() {
  if (http_request.readyState == 4) {
    if (http_request.status == 200) {
      var cadCodificadaJSON = http_request.responseText;
      var objDatos = eval("(" + cadCodificadaJSON + ")"); //Creamos el objeto utilizando la cadena codificada
      //Ahora con el objeto desplegamos los datos mandados desde el servidor
      document.getElementById("divId").innerHTML = objDatos.id;
      document.getElementById("divNombre").innerHTML = objDatos.nombre;
      document.getElementById("divCategoria").innerHTML = objDatos.categoria;
      document.getElementById("divPrecio").innerHTML = objDatos.precioDeSalida;
      document.getElementById("divDetalles").innerHTML = objDatos.detalles[0] + ", " + objDatos.detalles[1] + ", " + objDatos.detalles[2];
    } else {
      alert("Ocurrio un problema con la URL.");
    }
    http_request = null;
  }
}
</script>
</head>
<body>
<h2>Producto</h2>
<div id="divId"></div>
<div id="divNombre"></div>
<div id="divCategoria"></div>
<div id="divPrecio"></div>
<div id="divDetalles"></div>
</body>
</html>


Este código implementa una sencilla aplicación AJAX, similar a las vistas en los primero ejemplos sobre esta tecnología vistos en este blog. Básicamente accede a la aplicación en PHP que creamos previamente, y procesa el texto plano que recibe como respuesta, almacenándolo en la cadena, debido a que este texto consiste en la codificación en JSON del objeto original, lo decodifica utilizando la instrucción eval("(" + cadCodificadaJSON + ")"), creando el objeto objDatos como resultado.

El resultado obtenido se vería en el navegador como sigue:

Producto


1

Nintendo DS

Videojuego

$3 500

Soporta juegos para Gameboy advance, Pantalla tactil, Reproducción de MP3


De esta forma, podemos transmitir conjuntos de datos estructurados sin recurrir a formatos como XML o protocolos como SOAP, que requieren un mayor trabajo de procesamiento de la información en el cliente, pero que en contra parte, exige que el servidor pueda llevar a cabo la codificación de objetos en JSON. La elección final de la forma en que vayamos a transmitir los datos sobre HTTP, dependerá de los requerimientos que nos exijan la arquitectura y la plataforma que habremos de utilizar.

Saludos.

miércoles, 27 de mayo de 2009

Notas para iniciarse en PHP, Parte 6: Clases y objetos en PHP5


Un nuevo modelo de objetos

En la versión 5 de PHP se introdujo un nuevo modelo de objetos, rehaciendo completamente el anterior, para mejorar el funcionamiento y agregar nuevas características, en beneficio del programador por fortuna.

El cambio de modelos

Como mencionamos en el artículo anterior, la definición de una clase esta integrada por un conjunto de componentes que aparecen dentro de una estructura. Para definir una clase se utilizará nuevamente la palabra "class", seguida del nombre de la clase y la apertura y cierre de corchetes, dentro de los cuales se declararán los componentes de ésta. Hasta aquí no se ve diferencia con el modelo anterior sin embargo, durante la declaración de los componentes de la clase es cuando tenemos los primeros cambios, ya que ahora se toma en cuenta la visibilidad de los campos (también llamados propiedades en el manual) y los métodos, por ejemplo si tomamos la clase Carrito del artículo anterior y la migramos a la versión 5 del lenguaje tenemos un resultado como el que sigue:

class Carrito {
public $items; // Ítems en nuestro carrito de compras

// Agregar $num artículos de $artnr al carrito

public function agregar_item($artnr, $num) {
$this->items[$artnr] += $num;
}

// Tomar $num artículos de $artnr del carrito

public function retirar_item($artnr, $num) {
if ($this->items[$artnr] > $num) {
$this->items[$artnr] -= $num;
return true;
} elseif ($this->items[$artnr] == $num) {
unset($this->items[$artnr]);
return true;
} else {
return false;
}
}
}


Es la clase Carrito con los métodos que ya vimos antes, sin embargo tanto al único campo como a los métodos se les antepuso la palabra public, que es un indicador de visibilidad, esto se debe a que el modelo de objetos de PHP5 tenemos que indicar el tipo de visibilidad de los métodos y propiedades de nuestras clases, la cual especifica el contexto en el que estos componentes podrán ser utilizados. La declaración public indica que el método puede ser utilizado en el contexto en el que se instancie la clase, es decir donde se cree un objeto de esta clase, por ejemplo si instanciamos la clase Carrito:

$carrito = new Carrito;
$carrito->agregar_item("10", 1);
$carrito->agregar_item("8", 3);
$carrito->agregar_item("110", 4);
$carrito->retirar_item("8", 2);


Podemos acceder a los métodos agregar_item o retirar_item debido a que su indicador de visibilidad es public, de haber utilizado protected o private esto no habría sido posible, ya que protected determina que los métodos y propiedades solo pueden ser utilizados dentro de la definición de la propia clase y en la de sus clases extendidas, mientras que private restringe el uso de los métodos y propiedades únicamente a la declaración de la misma clase .

El concepto de visibilidad se introdujo en esta versión es una de las principales diferencias que encontraremos durante el trabajo con las clases, y lo primero a lo que debemos adaptarnos al migrar nuestra programación, el resto del trabajo consiste en conocer las nuevas funcionalidades que ofrece PHP para este modelo.

Instancia de una clase

Como se vio en el ejemplo anterior, la instanciación de clases se sigue haciendo de la misma manera que en la versión 4, solo hay que notar que algunas autores recomiendan que aunque no se pasen parámetros al constructor se incluya el paréntesis durante la instanciación, es decir:

$carrito = new Carrito();
Lo cual es totalmente opcional.

Herencia

El mecanismo para la herencia sigue siendo la extensión de clases con "extends" como en la versión 4.

Autocarga de objetos

Esta es una facilidad que brinda PHP para acceder a los archivos fuente de nuestras clases, que es útil cuando el nombre del archivo es el mismo que el de la clase que contiene. Anteriormente se tenía que realizar un include para cada archivo, mientras que ahora se cuenta con una función que puede hacer ese trabajo por nosotros.

Si declaramos en nuestro programa la función __autoload() PHP la llamará automáticamente cada vez que se haga una nueva instancia a una clase que no ha sido incluida aún, esta función recibe el nombre de la clase como parámetro y dentro de ella podemos realizar la inclusión del archivo, por ejemplo:

<?php
function __autoload($class_name) {
require_once $class_name . '.php';
}

$obj = new MyClass1();
$obj2 = new MyClass2();
?>


En este ejemplo no existe dentro del programa la definición de la clase MyClass1, entonces al hacer la instancia PHP ejecutará por si solo la función __autoload() y le pasará como parámetro el nombre de la clase que estamos llamando, es decir que la función recibirá "MyClass1" en su parámetro $class_name, entonces teniendo el nombre de la clase y sabiendo que es el mismo nombre del archivo que la contiene, podemos incluir este archivo con la función require_once.

Constructores y destructores

La declaración de un constructor ahora es diferente, ya no se utiliza el nombre de la clase para identificarlo sino el nombre especial __contruct, de modo que la función que declaremos con este identificador será llamada cada vez que se cree un nuevo objeto de nuestra clase:

<?php
class BaseClass {
function __construct() {
print "In BaseClass constructor\n";
}
}

class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "In SubClass constructor\n";
}
}

$obj = new BaseClass();
$obj = new SubClass();
?>


El ejemplo anterior nos muestra no solo la declaración de un constructor de un clase sino también que el constructor de una clase padre no es llamado implícitamente por el constructor de sus hijos, por lo que tiene que debe ser llamado explícitamente con partent::__contruct(). La principal ventaja de utilizar el mismo nombre para todos los constructores, es que al momento de cambiar el nombre de una clase no tendremos que hacer lo mismo con su contructor.

El método __destruct() es el destructor de la clase, este es un nuevo tipo de método que se incluyó como una de las novedades de PHP5, el cual es ejecutado cuando todas las referencias al objeto de la clase sean removidas, o cuando el objeto sea explícitamente destruido, o cuando llegue la finalización de un programa.

<?php
class MyDestructableClass {
function __construct() {
print "In constructor\n";
$this->name = "MyDestructableClass";
}

function __destruct() {
print "Destroying " . $this->name . "\n";
}
}

$obj = new MyDestructableClass();
?>


Este método tampoco es llamado implícitamente en los destructores de las clases hijo, por lo que de querer ejecutar el destructor del padre debería llamarse con parent::__destruct().

Elementos estáticos y constantes

Dentro de los componentes de una clase pueden existir miembros estáticos, es decir propiedades y métodos accesibles fuera de la definición de la propia clase que no necesitan de un objeto para ser utilizados, sino que pueden accederse directamente con el operador de resolución de contexto '::'. Estos componentes estáticos no pueden ser redefinidos en la extensión de una clase.

<?php
class Foo {
public static $prop = "Propiedad estática";
public static function aStaticMethod() {
echo "Método estático que es accesible sin un objeto";
}
}

Foo::aStaticMethod();
echo Foo::$prop;
?>


Para acceder a una propiedad o método estático dentro de la definición de la misma clase, se utiliza la palabra 'self' junto con el operador de resolución de contexto '::' como se indica:

class Foo
{
public static $my_static = 'foo';

public function staticValue() {
return self::$my_static;
}
}


También pueden existir propiedades constantes es decir, valores que no pueden ser alterados y que tienen un identificador para acceder a ellos. Las constantes difieren de las variables normales en que no se usa el símbolo $ para declararlas o usarlas. Para leer sus valores desde el contexto de la definición de la clase se utiliza la palabra 'self' seguida del operador '::' junto con el identificador de la constante. Desde el contexto de la instancia no se puede acceder a las contantes como una propiedad de los objetos, sino que se accede directamente a ellas a través de la clase con el operador de resolución de contexto '::'.

<?php
class MyClass
{
const constant = 'constant value';

function showConstant() {
echo self::constant . "\n";
}
}

echo MyClass::constant . "\n";

$class = new MyClass();
$class->showConstant();
// echo $class::constant; No es una operación permitida
?>
Su modo de acceso es similar al de las propiedades estáticas como se puede ver, con la diferencia de que las propiedades constantes no pueden ser alteradas. En ambos casos si deseamos acceder a una propiedad estática o constante de la clase padre desde un método del hijo, debemos utilizar la palabra 'partent', tal como se vió su uso en las secciones anteriores.

Abstracción de datos e interfaces

Otra de las novedades de esta versión son las clases abstractas, las cuales nos permiten crear clases no instanciables que funcionan como base para las clases hijo que las extenderán. Las clases abstractas pueden contener métodos abstractos, es decir métodos de los que solo aparece su declaración en la clase base y que forsozamente tienen que ser definidos en las clases hijo.

Las clases abstractas son útiles cuando tenemos un grupo de clases que compartirán un comportamiento en común y al mismo tiempo implementarán funcionalidades particulares, para lo cual podemos crear una clase base que indique la estructura general que tendrán todos las clases extendidas. La diferencia con el tipo de herencia común es que las clases abstractas se utilizarán cuando no necesitemos implementar el comportamiento de la clase base dentro de nuestros programas.

Siguiendo con la revisión también nos encontramos que existen interfaces, que consisten en estructuras similares a las clases abstractas ya que no pueden instanciarse, y dentro de su definición también hayamos propiedades y métodos, pero tienen la gran diferencia de que en una interface solo se declaran los métodos, estos nunca se definen, de esta tarea se encargarán las clases que las implementen. Como se pueden dar cuenta, mencione que las clases implementarán las interfaces, y es que aquí se habla de implementación en lugar de extensión, a pesar de ser mecanismos similares se hace la diferencia, ya que en el caso de las interfaces las clases que las implementan nunca heredan un método funcional. Entonces estas estructuras especifican qué métodos deberán poseer las clases que los implementen, y dejarán los detalles de la implementación a estas clases.

Las interfaces tienen gran utilización dentro de los lenguajes orientados a objetos para estandarizar ciertas funciones, al establecer los comportamientos que deberán seguir los objetos que implementen alguna funcionalidad particular. Por ejemplo, dentro de Java se utilizan para implementar el manejo de eventos del usuario, ya que si deseamos que alguna de nuestras clases pueda capturar algún evento del teclado o ratón, necesitan implementar una interfase que proporciona el lenguaje para el manejo de estos eventos, de forma que sin conocer los detalles sobre el manejo de eventos, sabremos que métodos deberemos implementar dentro de nuestras clases para utilizarlo. Algo similar puede verse en otros lenguajes, incluyendo a PHP, para crear frameworks de programación, ya que de esta forma podemos establecer que comportamiento deberá tener una clase que desee implementar cierta funcionalidad contemplada en el armazón.

La palabra reservada 'final'

Cuando se desea que las clases hijo no puedan redefinir un método o modificar el valor de una propiedad de la clase padre, se puede utilizar la palabra reservada final durante su declaración, con la cual PHP interpretará que este valor no podrá ser alterado fuera del contexto de su clase, lanzando un error de querer hacerlo.

Otras funcionalidades

PHP ofrece además de lo anterior algunas opciones adicionales que podemos utilizar con nuestras clases para obtener ciertas facilidades, como son:

El acceso a miembros y sobrecarga de métodos. Se usan para registrar nuevas propiedades en los objetos en tiempo de ejecución y para implementar la sobrecarga de métodos.
La interacción con objetos. Últil para desplegar las propiedades de un objeto desde un foreach.
Patrones. Sirven para implementar funcionalidades comunes en nuestros programas que nos ahorren tiempo de programación.
Clonación de objetos. Nos permite hacer replicas de nuestros objetos.

Y con esta última revisión termino con mis anotaciones sobre el modelo de objetos de PHP5, ahora lo que queda por ver es la forma en la que podemos utilizar todo lo aprendido interactuando con las interfaces de usuario, para lo que revisaremos la lectura de datos de formularios, el manejo de sesiones y cookies, y algunas funciones que hacen varias cosas interesantes.

Hasta la próxima.