Plantilla:PHP/PDO
De WikiEducator
Revisión a fecha de 07:03 8 ene 2020; ManuelRomero (Discusión | contribuciones)
Contenido
Qué es PDO
- La extensión PDO (PHP Data Objects) permite acceder a diferentes gestores de bases de datos utilizando las misma funciones.
- Esto es una gran ventaja frente a la extensión vista anteriormente mysqli,
- PDO nos abstrae de forma completa el sistema gestor que se utiliza.
- Como comentamos en el tema anterior, necesitaremos el driver concreto dependiendo del sistema gestor de bases de datos.
- Esto es lo único que tendremos que cambiar en nuestro programa para que funcione en uno u otro gestor de bases de datos, sin tener que cambiar nada del sql.
- En PHP 5 existen drivers para acceder a las bases de datos más populares (MySQL, Oracle, MS SQL Server, PostgreSQL, SQLite, Firebird, DB2, Informix, etc).
- En el siguiente enlace podemos ver los controladores de PDO que soporta directamente php.
http://es.php.net/manual/es/pdo.drivers.php
- En esta lección se explica el acceso a MySQL y SQLite mediante PDO. La extensión PDO no evalúa la correción de las consultas SQL.
Establecer conexión con PDO
- Para establecer una conexión lo que hacemos es instanciar un objeto de la clase PDO
$conexion = new PDO(...);
El constructor tien 4 parámetros de los cuales sólo el primero es obligatorio
- Origen de datos (DSN).
- Este parámetro es un string que la información del controlador del driver que voy a utilizar y se especifica de la siguiente manera
controlador:parametro1=dato1;parametro2=datos...parametron=daton
- Los parámetros a especificar dependerá del controlador que vamos a utilizar, en general me informarán del controlador del driver que voy a utilizar como por ejemplo el nombre o dirección IP del servidor, el nombre de la base de datos).
- Por ejemplo en el caso del controlador mysql
$conexion = new PDO('mysql:host=localhost;dbname=dwes', ...);
- Nombre de usuario
- Contraseña del usuario.
- Opciones de conexión, almacenadas en forma de array.
- Muchas de las opciones de conexión dependerán del driver que vayamos a utilizar
- Por ejemplo con mysql podemos verlas aquí http://php.net/manual/es/ref.pdo-mysql.php
(Ver dentro de cada página de controladores http://php.net/manual/es/pdo.drivers.php)
Conxión con mysql
- En el caso de mysql en parámetro DNS tendríamos los siguientes datos
- host Nombre o dirección IP del servidor.
- port Número de puerto TCP en el que escucha el servidor.
- dbname Nombre de la base de datos.
- unix_socket Socket de MySQL en sistemas Unix.
- Como podemos ver en el ejemplo anterior, no todos los datos del parámetro DNS son obligatorios, podemos establecer la conexión con host y dbname.
- Respecto a las opciones de conexión permiten establecer varios cuestiones
- Una vez establecida la conexión se pueden consultar/acutalizar valores de opciones de la conexión usando los métodos
getAtribute(int $atributo); setAtribute(int $atributo, mixed $valor);
- Podemos ver los atributos en la página http://es.php.net/manual/es/pdo.setattribute.php http://es.php.net/manual/es/pdo.getattribute.php
Realizar consultas con PDO
- En el caso de PDO, se diferencias las consultas que retornan datos (SELECT) y las que actúan sobre el contendio de los datos (INSERT, UPDATE, DELETE)
- INSERT, OPDATE, DELETE
- En este caso la sentencia se ejecuta envíandola con el método exec($sentencia)
- Este método retorna un entero que indica en número de registros afectados
$conexion= NEW PDO("mysql:host=localhost;db=dwes","root","root"); $registros = $conexion->EXEC("DELETE FROM stock WHERE unidades=0"); print "<p>Se han borrado $registros registros.</p>";
- SELECT
- En este caso debemos usar el método de la clase PDO llamado query($consulta)
- Este método retorna un objeto de la clase PDOStatement http://es1.php.net/manual/es/class.pdostatement.php
- Una vez que tenemos el objeto de la clase ya tenemos ese cursor o conjunto de filas con su puntero
- Para extraer cada fila usamos el método fetch(), el cual en caso de que no haya filas que retornar devuelve null (El mismo concepto trabajado hasta ahora).
- Cada vez que hacemos un fetch obtenemos un array con la fila que podemos usar tanto de forma asociativa como indexada.
- Este comportamiento por defecto se puede cambiar, es decir que podemos obligar a que el array que devuelve sea indexado, asociativo o que sea un objeto.
- Para ello debemos pasar al método fetch un valor que lo especifique según la lista siguiente.
- Para cerrar el cursor se emplea el método closeCursor(); muchos gestores de bases de datos necesitas que se libere, antes de ser usado para realizar otra consulta.
- PDO::FETCH_ASSOC. Devuelve solo un array asociativo.
- PDO::FETCH_NUM. Devuelve solo un array con claves numéricas.
- PDO::FETCH_BOTH. Devuelve un array con claves numéricas y asociativas. Es el comportamiento por defecto.
- PDO::FETCH_OBJ. Devuelve un objeto cuyas propiedades se corresponden con los campos del registro.
- A continuación diferentes formas de hacer exactamente lo mismo
$conexion = new PDO("mysql:host=localhost;dbname=dwes", "dwes", "abc123."); $resultado = $conexion->query("SELECT producto, unidades FROM stock"); while ($registro = $resultado->fetch()) { echo "Producto ".$registro['producto'].": ".$registro['unidades']."<br />"; }
$conexion = new PDO("mysql:host=localhost;dbname=dwes", "dwes", "abc123."); $resultado = $conexion->query("SELECT producto, unidades FROM stock"); while ($registro = $resultado->fetch(PDO::FETCH_ASSOC)) { echo "Producto ".$registro['producto'].": ".$registro['unidades']."<br />"; }
$conexion = new PDO("mysql:host=localhost;dbname=dwes", "dwes", "abc123."); $resultado = $conexion->query("SELECT producto, unidades FROM stock"); while ($registro = $resultado->fetch(PDO::FETCH_NUM)) { echo "Producto ".$registro[0].": ".$registro[1]."<br />"; }
$conexion = new PDO("mysql:host=localhost;dbname=dwes", "dwes", "abc123."); $resultado = $conexion->query("SELECT producto, unidades FROM stock"); while ($registro = $resultado->fetch(PDO::FETCH_OBJ)) { echo "Producto ".$registro->producto.": ".$registro->unidades."<br />"; }
$conexion="mysql:host=localhost;dbname=dwes"; $user="root"; $pass="root"; $opciones=array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"); $conexion=new PDO($conexion,$usuario,$pass, $opciones); $consulta = "Select * from ..."; $sentencia = "Insert into ....." $resultado = $conexion->exec($sentencia); $resultado->closeCursor(); echo "Se han insertado $resultado filas"; $resultado = $conexion->query($sconsulta); while $resultado->fetch(){ echo "se la leído el valor $resultado[0], ..."; } $conexion=null; //Es la manera de liberar a la memoria de este objeto. |
Consultas preparadas
- Al igual que en mysqli, podemos preparar las consultas. Esta forma de trabajar es cómoda y mas segura que la habitual, según viemos en apartados anteriores
- Para realizar una consulta parametrizada, hay que seguir unos pasos al igual que en mysqli
- preparar la consulta prepare(...)
- Para ello se pueden pasar con ? los valores de los parámetros o bien poner un nombre precedido de :
$conexion = new PDO("mysql:host=localhost;dbname=dwes", "dwes", "abc123."); $consulta = $conexion->prepare('INSERT INTO familia (cod, nombre) VALUES (?, ?)');
Es igual que hacer
$conexion = new PDO("mysql:host=localhost;dbname=dwes", "dwes", "abc123."); $consulta = $conexion->prepare('INSERT INTO familia (cod, nombre) VALUES (:codigoProducto, :nombreProducto)');
- Asignar valores a la consulta pararmetrizada
- Si se han especificado ? se asigna dando a cada parámetro un valor con el método bindParam(posicion, valor)
$cod_producto = "TABLET"; $nombre_producto = "Tablet PC"; $consulta->bindParam(1, $cod_producto); $consulta->bindParam(2, $nombre_producto);
- Si se han especificado con nombre se usan los nombre en lugar de los números
$cod_producto = "TABLET"; $nombre_producto = "Tablet PC"; $consulta->bindParam(":cod", $cod_producto); $consulta->bindParam(":nombre", $nombre_producto);
- Se ejecuta con el método execute()
- Este método permite alternativamente suplir las asignaciones anteriores realizadas con el método bindParam, pasándole en un argumento meditante una array dicha asignación.
- El array utilizado será asociativo o con claves numéricas dependiendo de la forma en que hayas indicado los parámetros.
- En el primer caso
$parametros = array[":nombre","TABLET"]; $consulta->execute($parametros);
- En el segundo caso
$parametros = array(":cod" => "TABLET", ":nombre" => "Tablet PC"); $consulta->execute($parametros);
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <?php $dns = "mysql:host=localhost; dbname=dwes"; $user='root'; $pass='root'; $opciones= array( PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"); //Realizamos una conexión básico pdo $conexion = new PDO($dns, $user, $pass, $opciones); if ($conexion) echo "conexión realizada satisfactoriamente"; else echo "ohhhh!!!! no se ha conectado"; //Ahora planteamos una sentencia de tipo insert $sentencia = "insert into producto values('NEW_PRODUCTO12','NOMBRE_PRODUCTO','NOMBRE_CORTO','DESCRIPCION DESCRIPCION',10000,'MP3')"; //Y planteamos tambión una sentencia select $consulta ="select nombre_corto from producto"; $filas= $conexion->exec($sentencia); echo"Se ha insertado correctamene $filas"; //$filas será un objeto del tipo PDOStatement $filas= $conexion->query($consulta); while ($fila=$filas->fetch()){ echo "Se ha recuperado $fila[0]<br/>"; } $filas->closeCursor(); $conexon=null; //Ahora hacemos la consulta parametrizadas //usando un objeto de la clase PDOStatement //Hacemos el prepare $sentencia= "Select producto from stock where tienda = :nom"; $consulta = $conexion->prepare($sentencia); $tienda =3; //$consulta->bindParam(':nom',$tienda,PDO::PARAM_INT); //$consulta->execute(); //Podemos usar la opción de antes o esta otra $consulta->execute(array(":nom"=>$tienda)); //Ahora mostramos los resultados while ($fila=$consulta->fetch()){ echo "Visualizo el producto $fila[0]<br/>"; } ?> </body> </html>
|
Control de excepciones
- A partir de la versión 5 se introdujo en PHP un modelo de excepciones similar al existente en otros lenguajes de programación:
- El código susceptible de producir alguna situación de excepción, la cual produciría un error en ejecución, se puede introduce en un bloque try - catch, con la intención de controlar dicho error de ejecución o excepción (por ejemplo dividir por cero).
try{ //Instrucciones que pueden lanzar una excepción y //puedo capturar en tiempo de ejecución }cathc(Exception $e){ echo "Se ha producido una excepcion". $e->getMessage(); }
- Cuando se producen estas situaciones de excepción que queremos controlar, antes de que se produzcan, se lanza una excepción utilizando la instrucción throw.
- Después del bloque try debe haber como mínimo un bloque catch encargado de procesar dicha excepción.
- Si una vez acabado el bloque try no se ha lanzado ninguna excepción, se continúa con la ejecución en la línea siguiente al bloque o bloques catch.
- PHP ofrece una clase base Exception para utilizar como manejador de excepciones.
- Esta clase implementa dos métodos generales que nos muestran información sobre la excepticon que se ha podido producir
- getMessage. Devuelve el mensaje, en caso de que se haya puesto alguno.
- getCode. Devuelve el código de error si existe.
- El caso de PDO define su propia clase de excepciones que deriva o hereada de la clase Exception
- Para el caso concreto de PDO, hay que configurar para que lance las excepciones, puediento esta configuración tomar los siguientes valores:
- PDO::ERRMODE_SILENT. No se hace nada cuando ocurre un error. Es el comportamiento por defecto.
- PDO::ERRMODE_WARNING. Genera un error de tipo E_WARNING cuando se produce un error.
- PDO::ERRMODE_EXCEPTION. Cuando se produce un error lanza una excepción utilizando el manejador propio PDOException.
- Vamos a ver como se utiliza:
- Primero activamos las excepciones, y luego ya se pueden utilizar
$dwes = new PDO("mysql:host=localhost; dbname=dwes", "dwes", "abc123."); $dwes->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); try { $sql = "SELECT * FROM stox"; $result = $dwes->query($sql); //… } catch (PDOException $p) { echo "Error ".$p->getMessage()."<br />"; }
- En este caso que no existe la tabla nos diría
Error SQLSTATE[42S02]: Base table or view not found: 1146 Table 'dwes.stox' doesn't exist
- En el caso de mysqli usaríamos la clase mysqli_sql_exception que gestiona el tema de las excepciones
http://es.php.net/manual/es/class.mysqli-sql-exception.php
|
Excepciones en PDO
En PDO tenemos 3 niveles de controlar situaciones de excepción. Cada nivel corresponde a cada uno de los valores que a continuación comentamos.
- Para establecer el nivel de excepción se puede hacer de dos maneras
- Al establecer la conexión, estableciendo el tercer parámetro del constructor PDO, usando el índice
- Usando el método setAtribute() del objeto de la conexión PDO.
Cada nivel tiene una mayor o menor profundidad en el detalle de información que da en un determinado error de ejecución. Por ejemplo si no podemos conectar a una tabla de una base de datos por