Clase PHP para MySQL

Base de datos

En las últimas versiones de PHP, el soporte para programación orientada a objetos mejoró considerablemente. A día de hoy, que cualquier proyecto medianamente complejo desarrollado en PHP esté basado en POO es prácticamente una necesidad.

En nuestros proyectos, pequeños o grandes, usar clases es una gran ventaja. Sobre todo si las diseñamos con cierta perspectiva y pensando en su reutilización. Empezamos ahora una serie de artículos sobre el encapsulamiento de algunas herramientas que usaremos frecuentemente en proyectos PHP. La idea es mejorar nuestro rendimiento y el de nuestras páginas, reutilizando códigos tan optimizados como seamos capaces de escribir.

Aunque PHP ya tiene diseñadas clases para estas tareas (por ejemplo, mysqli), a veces es más cómodo usar las nuestras. Ya sé que esto está en contra de la reutilización, y que es "reinventar la rueda". Teniendo todo esto en cuenta, consideremos esto como un ejercicio. :)

Tanto más si tenemos en cuenta las recomendaciones que aparecen en la documentación de PHP:

Esta extensión está obsoleta a partir de PHP 5.5.0 y no está recomendada para escribir código nuevo, ya que será eliminada en el futuro. En su lugar, se debería utilizar la extensión mysqli o PDO_MySQL.

Al final veremos como usar la clase mysqli, en lugar de la nuestra.

Nuestras clases para bases de datos

Empecemos con un par de clases para acceder a bases de datos MySQL.

<?php
    /*  Clase mySQLDB para acceder a bases de datos mySQL.
        Clase queryDB para realizar consultas en una base de datos.
    */
    class mySQLDB {
        const servidor = 'host'; /* Sustituir por valor adecuado */
        const usuario  = 'user'; /* Sustituir por valor adecuado */
        const clave    = 'password'; /* Sustituir por valor adecuado */
        protected $IdConexion;
        protected $basedatos;

        function __construct() {
            $this->IdConexion = @mysql_connect(self::servidor, self::usuario, self::clave)
                or die ('Imposible conectar con base de datos.');
        }

        function __destruct() {
            @mysql_close($this->IdConexion);
        }

        function SetBaseDatos($nombrebd) {
            $this->basedatos = $nombredb;
            @mysql_select_db( $nombredb, $this->IdConexion);
        }

        function GetConexion() {
            return $this->IdConexion;
        }

        function GetBaseDatos() {
            return $this->basedatos;
        }
    }

    class queryDB {
        protected $BD;
        protected $Id;

        function __construct( $Bd, $Query ) {
            $this->BD = $Bd;
            $this->Id = @mysql_query( $Query, $this->BD->GetConexion() );
        }

        function __destruct() {
            @mysql_free_result($this->Id);
        }

        function Cerrar() {
            @mysql_free_result($this->Id);
        }
        function NumRows() {
            return @mysql_num_rows($this->Id);
        }

        function FetchArray() {
            return @mysql_fetch_array($this->Id);
        }
    }
?>

En la definición de las clases anteriores quiero llamar la atención sobre algunas cosas.

  1. El carácter '@' antes de las llamadas a las funciones 'mysql_' es para evitar que se muestren los mensajes de aviso que se producen cuando se usan funciones obsoletas. Antes he mencionado que la extensión "mysql" está considerada obsoleta a partir de PHP 5.5.
  2. En el constructor de la base de datos incluimos el código necesario para establecer la conexión, y en el destructor, cerramos esa conexión. Esto libera a nuestra aplicación de la tarea de abrir y cerrar conexiones a bases de datos, ya que estas se realizan de forma automática.
  3. SetBaseDatos asigna una base de datos por defecto a la conexión. Podremos cambiar esta base de datos cuando queramos, o ignorarla, incluyendo el nombre completo de la tabla en las consultas, basededatos.tabla.
  4. GetBaseDatos permite recuperar el nombre de la base de datos por defecto.
  5. GetConexion nos devuelve el identificador de la conexión asociada a la base de datos, aunque probablemente nunca necesitemos usarla.
  6. En este ejemplo he optado por crear clases separadas para bases de datos y consultas, aunque se podrían haber creado ambas usando una única clase.
  7. El constructor de la clase queryDB almacena una variable con la base de datos y un identificador a la consulta creada. Para ello se necesitan dos parámetros, que son la base de datos y la cadena con la consulta.
  8. El destructor libera los resultados asociados a la consulta.
  9. El método Cerrar nos permite liberar los resultados de la consulta cuando sea necesario. Por ejemplo, no será posible hacer una consulta en una base de datos hasta que la anterior haya sido cerrada. Si hacemos dos consultas en el mismo método será necesario cerrar la primera antes de hacer la segunda.
  10. NumRows recupera el número de filas que contiene el resultado de la consulta.
  11. FetchArray recupera una fila o tupla de la consulta.

Usar estas clases en una aplicación es muy sencillo. Por ejemplo:

    $database = new mysqlDB();
    $Consulta = new queryDB( $database, "SELECT * FROM agenda.personas ORDER BY nombre");
    print("<table>\n");
    print("<tr><th>Nombre</th><th>Fecha</th></tr>\n");
    for( $i = 0; $i < $Consulta->NumRows(); $i++) {
        $reg = $Consulta->FetchArray();
        print("<tr><td>".$reg["nombre"]."</td><td>".$reg["fecha"]."</td></tr>\n");
    }
    $Consulta->Cerrar();
    print("</table>\n");

Esta es una de muchas posibles implementaciones, simplificada a propósito, ya que no proporciona soporte para la mayor parte de las funciones de la extensión mysql. Sin embargo, resulta bastante útil, y es una buena muestra de las ventajas de encapsular que proporciona la programación orientada a objetos.

Usando la clase Mysqli

PHP dispone de una extensión para acceso a MySQL que en la documentación se denomina "extensión MySQL mejorada".

Consta no de dos clases, sino de seis, aunque tres de ellas son de utilidad limitada para la mayoría de las aplicaciones: mysqli_driver, mysqli_warning y mysqli_sql_exception.

Nos centraremos en las otras tres.

Para ver una documentación completa de estas clases recomiendo acceder a la página de PHP.

La clase mysqli

El constructor tiene cierto parecido al nuestro, los tres primeros parámetros son los mismos. Se puede añadir un cuarto, con el nombre de la base de datos por defecto, un quinto con el puerto de conexión y un sexto con el socket. Aunque los seis parámetros son opcionales, seguramente querremos usar los tres o cuatro primeros siempre. Por supuesto, este constructor crea o intenta crear la conexión con la base de datos.

El método query permite realizar consultas. El primer parámetro es la cadena con la consulta, el segundo es opcional, y permite seleccionar el modo en que se trata el resultado. Por defecto es MYSQL_STORE_RESULT, que indica que el resultado será almacenado. Si se usa MYSQL_USE_RESULT los resultados de la consulta no serán almacenados. Esto es poco aconsejable si se realizan muchas actualizaciones desde el lado del cliente, ya que las tablas consultadas se bloquean.

El método select_db permite seleccionar una base de datos por defecto.

Otro dato miembro interesante es $insert_id, que contiene el identificador de la última fila insertada en una columna autoincrementada.

La clase mysqli_result

El método query devuelve un objeto de la clase mysqli_result. En esta clase hay, entre otros, los siguientes datos y métodos:

El dato $num_rows contiene el número de filas de un resultado.

El método fetch_array obtiene una fila desde el conjunto de resultados.

El método free (o sus alias close y free_result) liberan la memoria asociada al resultado.

La clase mysqli_smtp

Esta clase se usa para realizar las consultas usando otro sistema, que requiere la preparación de la consulta, asociar columnas con variables, etc.

Será un tema para tratar en otra entrada del blog.

Ejemplo usando mysqli

    $database = new mysqli("localhost", "user", "password");
    $Resultado = $database->query( "SELECT * FROM agenda.personas ORDER BY nombre");
    print("<table>\n");
    print("<tr><th>Nombre</th><th>Fecha</th></tr>\n");
    for( $i = 0; $i < $Resultado->num_rows; $i++) {
        $reg = $Resultado->fetch_array();
        print("<tr><td>".$reg["nombre"]."</td><td>".$reg["fecha"]."</td></tr>\n");
    }
    $Resultado->free();
    print("</table>\n");

Como se puede apreciar, los ejemplos son muy parecidos.