domingo, 25 de marzo de 2007

PHP orientado a objetos

Leyendo el estupendo libro PHP5 & MySQL Bible, en el capítulo dedicado a la programación orientada a objetos con PHP, me encuentro con una nota al margen muy interesante:
"Do Web-Scripting Languages Really Need OOP?"


Sinceramente, creo que a veces se abusa un poco del paradigma de orientación a objetos. Considero que es una herramienta más, pero que no siempre es la más adecuada. En el caso de PHP encuentro que utilizar clases es una forma muy cómoda y limpia de agrupar código y funcionalidades.

Vamos a hacer una pequeña prueba con PHP, a ver qué sale (nota: utilizamos PHP 5). La tarea es trivial: un "script" que pinte una tabla a partir de los parámetros pasados. No hacemos ninguna validación. Es código "guarrete", sólo para probar.

Versión procedimental, con funciones:
<?php

function pinta_tabla($x, $y) {
$t0 = microtime(TRUE);
echo "";
for ($i=0; $i<$x; $i++) {
echo "";
for ($j=0; $j<$y; $j++) {
echo "";
}
echo "";
}
echo "
($i, $j)
";
$t1 = microtime(TRUE);
echo "Tiempo empleado: " . ($t1 - $t0)*1000 . "";
}

pinta_tabla($_GET['x'], $_GET['y']);

?>

Versión orientada a objetos:

<?php

class Tabla {
var $x, $y;
function __construct($x, $y) {
$this->x = $x;
$this->y = $y;
}
function pinta_tabla() {
$t0 = microtime(TRUE);
echo "";
for ($i=0; $ix; $i++) {
echo "";
for ($j=0; $jy; $j++) {
echo "";
}
echo "";
}
echo "
($i, $j)
";
$t1 = microtime(TRUE);
echo "Tiempo empleado: " . ($t1 - $t0)*1000 . "";
}
}

$tabla = new Tabla($_GET['x'], $_GET['y']);
$tabla->pinta_tabla();

?>

Vemos que esencialmente, las dos versiones hacen lo mismo. Tienen el mismo número de operaciones de E/S (dos búsquedas de variables GET y seis llamadas a echo).

A priori, sin tomar tiempos, podríamos pensar que la primera versión (procedimental) debe ser un poco más rápida, ya que no crea objetos en memoria ni tiene que buscar métodos en los objetos, etc.

Vamos a probarlo en local utilizando alguna herramienta de "benchmarking" como ab (Apache Benchmark):

Utilizaremos el comando ab -n 100 -c 1 "http://localhost/tabla.php?x=10&y=10", donde:

  • -n es el número de peticiones

  • -c es el nivel de concurrencia


Resultados, para -n 3000 y -c 1:






















PeticiónTiempo respuesta (ms)
http://localhost/tabla.php?x=10&y=102.552
http://localhost/tabla-oo.php?x=10&y=102.594
http://localhost/tabla.php?x=100&y=10040.484
http://localhost/tabla-oo.php?x=100&y=10043.896

La diferencia al pintar una tabla de 10 x 10 es del 1,65%. Si la tabla a pintar es de 100 x 100, la diferencia es del 7,8%. En este último caso si que se nota más diferencia, pero no nos olvidemos que son milisegundos.

El ejemplo es muy sencillo y realmente casi todo el tiempo de ejecución se dedica a recorrer los dos bucles anidados y a "pintar" datos. Pero nos deja una cosa clara: utilizar clases para organizar o estructurar mejor nuestro código no supone mucha sobrecarga (al menos en estos casos tan sencillos).

Sería interesante repetir los resultados con diferentes versiones de PHP en diferentes S.O. Me lo pongo como deberes ...