Simplificar la conexión PDO a Mysql con una clase PHP

Ejemplo de simplificación de conexión a base de datos encapsulando la clase PDO con una clase php propia.

objetos php conexión php PDO

En este tutorial voy a encapsular la funcionalidad de la clase PDO en una clase php propia. ¿Por qué hago esto? Pues para facilitarme la vida cuando programo, simplificar mi código y ganar velocidad al realizar un desarrollo web.

¿Qué es la encapsulación?

Este concepto da para un post entero, pero a modo de recordatorio o introducción voy a realizar una pequeña explicación: en la teoría el encapsulamiento es la ocultación de procesos internos complejos para dar acceso a unas funcionalidades concretas y simplificadas. El usuario (en este caso nosotros como programadores) de este desarrollo solo verá disponible unas funcionalidades básicas y esenciales (elegidas por nosotros) para realizar lo que se propone.

¿Y en la práctica? Mejor veamos un ejemplo real: Imagínate un piloto de avión, cuando se coloca a los mandos de la nave este no sabe si el avión por dentro está hecho con una u otra pieza, o si el estado del motor es óptimo. En cambio el piloto tiene a su alcance muchos botones y palancas del cuadro de mandos que, con solo pulsarlos o tirar de ellos, consigue que el avión despegue, accelere o ¡incluso activar el aire acondicionado!

El encapsulamiento es la ocultación de procesos internos para dar acceso en un uso determinado a unas funcionalidades concretas, el usuario (en este caso nosotros como programadores) de este desarrollo solo verá disponible unas funcionalidad básicas y esenciales para realizar lo que se propone.

¿Para qué me sirve encapsular la clase PDO?

La conexión y el uso de la clase PDO (por si no lo he dicho ya ¡me encanta!), puede ser tedioso, sobretodo si en nuestros desarrollos queremos mantener nuestra base de datos alejada de las manos de desaprehensivos y malintencionados. Mantener esta seguridad buscada, en consultas complejas, muchas veces consecutivas, o desarrollos web con una cantidad de consultas considerables, puede ser tedioso y costoso a lo que el tiempo respecta, sin hablar ya de la posibilidad de equivocarnos al escribir un comando u otro.

Encapsulando el uso de la clase PDO conseguimos que con un método y un número de parámetros adecuado a nuestras necesidades, podamos lanzar y lanzar consultas sobre nuestra base de datos usando la mitad o menos de líneas de código.

Como encapsular PDO en una clase propia

1.Atributos y  constructor

Al lío, vamos a crear una clase php llamada PDOAdmin. Como atributos de clase voy a definir un objeto de la clase PDO para guardar el objeto de la clase PDO, y otro objeto de clase PDOStatement para almacenar el resultado de las consultas que voy a ir lanzando.

<?php
class PDOAdmin{
     private $_pdo;
     private $_pdoStat;
}
?>

Ahora que tengo la clase y atributos, voy a añadirle su constructor. En el constructor voy a crear el objeto PDO con los datos de conexión introducidos como parametros de entrada, además, anticipándome a un futuro uso de la clase para conexión a distintas bases de datos, y hacerme la vida más fácil, voy a declarar los valores por defecto de la conexión en los parametros de entrada. En este ejemplo será una base de datos test, en localhost con user root y pass prueba, dejaré el array de opciones del constructor de PDO vacío ya que por defecto no necesito ninguna configuración extra:

function __construct($host = 'localhost', $dbname = 'test', $user = 'root', $pass = 'prueba', $options = array() ){      try {          $this->_pdo = new PDO('mysql:host='.$host.';dbname='.$dbname, $user, $pass, $options);      }catch (PDOException $e) {           print "¡Error!: " . $e->getMessage();           die();      } }

Como puedes ver, creo el objeto PDO y lo guardo en el atributo $_pdo de la clase. Prevengo un posible error de una conexión fallida con el try y catch y en caso de error lo imprimo con la función print y termino la ejecución php con die().

El código de la clase PDOAdmin con su constructor quedará así

<?php
class PDOAdmin{
     private $_pdo;
     private $_pdoStat;
     function __construct($host = 'localhost', $dbname = 'test', $user = 'root', $pass = 'prueba', $options = array() ){         
           try {             
               $this->_pdo = new PDO('mysql:host='.$host.';dbname='.$dbname, $user, $pass, $options);
           }catch (PDOException $e) {
               print "¡Error!: " . $e->getMessage();
               die();
           }     
     }
}
?>

 2. Métodos de la clase php

Como métodos de la clase necesitaré, a priori, tres:

  1. Método para lanzar las consultas
  2. Método para recuperar errores de las consultas
  3. Método para recuperar el id de la última inserción sobre la base de datos.
  4. Método para cerrar la conexión a la base de datos.

2.1 El método para lanzar consultas

Para lanzar consultas voy a crear un método llamado igual que el de la clase PDOStatement, execute(). Este metodo execute() necesitará una serie de parámetros de entrada para poder realizar las consultas ya sean INSERT SQL, SQL UPDATE DELETE SQL y además realizarlas con la seguridad proporcionada por el método bindParam.

Como parámetros de entrada necesitaré como mínimo dos: la consulta ($query) y otro parámetro ($return_rows) de configuración que me diga si tiene que devolver o no las filas del resultado, es decir si tengo que devolver las filas ya extraídas con fetchAll() o fetch(). Estos dos parámetros son los básicos y esenciales que podría utilizar en consultas sin ningúna clase de seguridad, pero como quiero tener la posibilidad de utilizar mis consultas con las opciones de seguridad de PDO, necesitaré dos parámetros más, un array con los valores de los interrogantes contenidos en la consulta ($array_valores), y otro array con los tipos correspondientes a cada valor introducido($array_tipos).

function execute($query = '', $return_rows = 0, $array_valores = array(), $array_tipos= array()){
    //código del método
}

Este método execute() de nuestra clase PDOAdmin encapsulará en su interior tres acciones:

  1. Preparar la consulta recibida en $query con el método prepare() del objeto PDO que tenemos en el atributo $_pdo y guardar en el atributo $_pdoStat el objeto resultado de la clase PDOStatment.
  2. Realizar los bindParam (si es necesario) de los parametros introducidos en $array_valores con su tipo $array_tipos y su posición que será la misma que ocupan en el interior del array.
  3. Devolver el resultado si $return_rows es 0 (en el caso de borrar o insertar), devolver las filas resultado de la consulta si $return_rows vale 1 o devolver una única fila si $return_rows vale 2.
2.1.1 Preparar la consulta recibida con prepare()

Con la siguiente línea de código guardamos, para su posterior uso, el objeto PDOStatement retornado por el método prepare() del objeto PDO:

$this->_pdoStat = $this->_pdo->prepare($query);

2.1.2 Realizar bindParam() de los parametros
foreach($array_valores as $posicion => &$valor){
      $tipo_var = 'STR' == $array_tipos[$posicion] ? PDO::PARAM_STR : PDO::PARAM_INT;
      $this->_pdoStat->bindParam($posicion+1, $valor, $tipo_var);
}

En este caso el bucle foreach() recorrerá los valores introducidos en el $array_valores y después asignará a una variable ($tipo_var) la constante de tipo de valor correspondiente del $array_tipos. Puedes ver que he usado la cadena 'STR' para marcar los valores de tipo VARCHAR y aunque no se visualice comentarte que usaré 'INT' para los enteros. Esta implementación es básica, aunque comprende el uso general de variables de una web sencilla. Para valores tipo DATE o decimales, etc. podríamos extender la funcionalidad del método con una comparación de otros tipos.

Por último realizo el bindParam() pasandole la posición del valor +1 ya que los arrays empiezan en 0 y los símbolos interrogantes de la consulta en 1. También le paso el valor recogido por referencia (de ahí el & del foreach junto a $valor) y la constante del tipo de valor en $tipo_var.

2.1.3 Devolver filas o resultado resultado de PDOStatement
$result = $this->_pdoStat->execute();
if( 0 < $return_rows && $result){
       return $return_rows == 2 ? $this->_pdoStat->fetch() : $this->_pdoStat->fetchAll();
}
return $result;

Poco que decir de este código, donde recojo el resultado de ejecutar la consulta en MySQL con execute() en $result y devuelvo las filas con fetchAll() o fetch() siempre que el parámetro de entrada $return_rows sea mayor que 0 y en caso contrario $result, ya sea un recurso o un false en caso de error.

2.2 Método para recuperar errores de PDO

function mostrar_error(){
      $array = $this->_pdoStat->errorInfo();
      var_dump($array);
}

El método mostrar_error() es un método que usaré para depurar y ver posibles errores en consultas, por lo tanto, se recupera el error con el método errorInfo() y muestro la información directamente con la función var_dump(). Feo pero útil, ejem.

2.3 Método recuperar último id insertado

A menudo nos encontramos con consultas que insertan filas de las que posteriormente queremos recuperar su identificador, para estos casos podemos usar el método lastInsertId() de la clase PDO. El siguiente método encapsula esa funcionalidad utilizando el mismo nombre:

function lastInsertId(){
     return $this->_pdo->lastInsertId();
}

2.4 Método disconnect() para cerrar la conexión PDO

Siempre debemos cerrar la conexión a la base de datos, de lo contrario, acumularemos más y más conexiones sin cerrar, piensa que cada acceso a una página será una nueva conexión. Esto será especialmente problemático en aplicaciones web con mucho tráfico.

function disconnect () {
    $this->_pdoStat->closeCursor();
    $this->_pdoStat = null;
    $this->_pdo = null;
}

3 Final, la clase PDOAdmin

Después de todo este trecho de texto que espero hayas leído (al menos en su mayoría) y sobretodo que te haya sido útil, te dejo la clase resultado:

<?php
class PDOAdmin{
     private $_pdo;
     private $_pdoStat;
     function __construct($host = 'localhost', $dbname = 'test', $user = 'root', $pass = 'prueba', $options = array() ){
          try {
              $this->_pdo = new PDO('mysql:host='.$host.';dbname='.$dbname, $user, $pass, $options);
          }catch (PDOException $e) {
              print "¡Error!: " . $e->getMessage();
              die();
          }
     }
     function execute($query = '', $return_rows = 0, $array_valores = array(), $array_tipos= array()){
           $this->_pdoStat = $this->_pdo->prepare($query);
           foreach($array_valores as $posicion => &$valor){
                   $tipo_var = 'STR' == $array_tipos[$posicion] ? PDO::PARAM_STR : PDO::PARAM_INT;
                   $this->_pdoStat->bindParam($posicion+1, $valor, $tipo_var);
           }
           $result = $this->_pdoStat->execute();
           if( 0 < $return_rows && $result){
                 return $return_rows == 2 ? $this->_pdoStat->fetch() : $this->_pdoStat->fetchAll();
           }
           return $result;
     }
     function mostrar_error(){
         $array = $this->_pdoStat->errorInfo();
         var_dump($array);
     }
     function lastInsertId(){
         return $this->_pdo->lastInsertId();
     }
        function disconnect () {
             $this->_pdoStat->closeCursor();
             $this->_pdoStat = null;
             $this->_pdo = null;
     }
}
?>

Sobre el autor

Javier Gómez Redactor en Srcodigofuente.es

Javier Gómez

Ingeniero técnico en informática de gestión. Desarrollador web freelance y profesor de desarrollo web a partes iguales. Testarudo autodidacta, creativo, perfeccionista y alma libre.

Cargando comentarios

Utilizamos "cookies" para información estadística. Si continúas navegando aceptas su uso.