PHP – clase PDO
En este post veremos de forma teórica lo que hace la clase PDO de la extension PDO en PHP y sus métodos. Veremos los siguientes temas:
- El funcionamiento de la clase PDO
- Los métodos de la clase PDO
- Cómo utilizar la clase PDO para conectar a una base de datos
- Cómo utilizar la clase PDO para realizar consultas a una base de datos
La clase PDO representa una conexión entre PHP y un servidor de bases de datos.
Sinopsis / Synopsisclass PDO { /* Constants */ public const int PARAM_NULL; public const int PARAM_BOOL = 5; public const int PARAM_INT = 1; public const int PARAM_STR = 2; public const int PARAM_LOB = 3; public const int PARAM_STMT = 4; public const int PARAM_INPUT_OUTPUT; public const int PARAM_STR_NATL; public const int PARAM_STR_CHAR; public const int PARAM_EVT_ALLOC; public const int PARAM_EVT_FREE; public const int PARAM_EVT_EXEC_PRE; public const int PARAM_EVT_EXEC_POST; public const int PARAM_EVT_FETCH_PRE; public const int PARAM_EVT_FETCH_POST; public const int PARAM_EVT_NORMALIZE; public const int FETCH_DEFAULT; public const int FETCH_LAZY; public const int FETCH_ASSOC; public const int FETCH_NUM; public const int FETCH_BOTH; public const int FETCH_OBJ; public const int FETCH_BOUND; public const int FETCH_COLUMN; public const int FETCH_CLASS; public const int FETCH_INTO; public const int FETCH_FUNC; public const int FETCH_GROUP; public const int FETCH_UNIQUE; public const int FETCH_KEY_PAIR; public const int FETCH_CLASSTYPE; public const int FETCH_SERIALIZE; public const int FETCH_PROPS_LATE; public const int FETCH_NAMED; public const int ATTR_AUTOCOMMIT; public const int ATTR_PREFETCH; public const int ATTR_TIMEOUT; public const int ATTR_ERRMODE; public const int ATTR_SERVER_VERSION; public const int ATTR_CLIENT_VERSION; public const int ATTR_SERVER_INFO; public const int ATTR_CONNECTION_STATUS; public const int ATTR_CASE; public const int ATTR_CURSOR_NAME; public const int ATTR_CURSOR; public const int ATTR_ORACLE_NULLS; public const int ATTR_PERSISTENT; public const int ATTR_STATEMENT_CLASS; public const int ATTR_FETCH_TABLE_NAMES; public const int ATTR_FETCH_CATALOG_NAMES; public const int ATTR_DRIVER_NAME; public const int ATTR_STRINGIFY_FETCHES; public const int ATTR_MAX_COLUMN_LEN; public const int ATTR_EMULATE_PREPARES; public const int ATTR_DEFAULT_FETCH_MODE; public const int ATTR_DEFAULT_STR_PARAM; public const int ERRMODE_SILENT; public const int ERRMODE_WARNING; public const int ERRMODE_EXCEPTION; public const int CASE_NATURAL; public const int CASE_LOWER; public const int CASE_UPPER; public const int NULL_NATURAL; public const int NULL_EMPTY_STRING; public const int NULL_TO_STRING; public const string ERR_NONE; public const int FETCH_ORI_NEXT; public const int FETCH_ORI_PRIOR; public const int FETCH_ORI_FIRST; public const int FETCH_ORI_LAST; public const int FETCH_ORI_ABS; public const int FETCH_ORI_REL; public const int CURSOR_FWDONLY; public const int CURSOR_SCROLL; /* Methods */ public __construct( string $dsn, ?string $username = null, ?string $password = null, ?array $options = null ) public beginTransaction(): bool public commit(): bool public errorCode(): ?string public errorInfo(): array public exec(string $statement): int|false public getAttribute(int $attribute): mixed public static getAvailableDrivers(): array public inTransaction(): bool public lastInsertId(?string $name = null): string|false public prepare(string $query, array $options = []): PDOStatement|false public query(string $query, ?int $fetchMode = null): PDOStatement|false public query(string $query, ?int $fetchMode = PDO::FETCH_COLUMN, int $colno): PDOStatement|false public query( string $query, ?int $fetchMode = PDO::FETCH_CLASS, string $classname, array $constructorArgs ): PDOStatement|false public query(string $query, ?int $fetchMode = PDO::FETCH_INTO, object $object): PDOStatement|false public quote(string $string, int $type = PDO::PARAM_STR): string|false public rollBack(): bool public setAttribute(int $attribute, mixed $value): bool }
__construct
Description / Descripciónpublic PDO::__construct( string $dsn, string $username = ?, string $password = ?, array $options = ? )Sintaxis / Sintax
$pdo_c = new PDO($dsn,$username,$password,$options);
Parametros
$dsn
– esta variable tiene contiene la información necesaria para conectarse a la base de datos en forma de string de la siguiente manera driver:dbname=database_name;host=host_ip
la mayoría de las veces, ya que podemos utilizar $dsn
de otras maneras también. Hay 3 maneras de utilizar $dsn
:
- Invocación del DNS completo
- Invocación del URI
- Mediante un alias
Invocación del DNS completo: La invocación completa es la que ya expresamos antes, driver:dbname=database_name;host=host_ip
por ejemplo, podría ser
$dsn = 'mysql:dbname=wpthemes;host=127.0.0.1';
suponiendo que poseemos una base de datos para un WordPress y su base sea wpthemes y utilizo MySQL como DBMS y nuestra base está alojada en nuestro localhost
Invocación de URI: En este método, el DSN se forma utilizando un URI que define la ubicación de un archivo. Este archivo puede estar en una ruta local o ser una URL remota.
Como $dns
de ejemplo, la página oficial de PHP nos da esta cadena, uri:file:///ruta/al/fichero_dsn
¿pero como definiríamos una ruta remota? Eso sería de la siguiente manera
$dsn = 'mysql://my_username:my_password@remote_host:remote_port/my_database';
Mediante un alias: de esta manera nuestro $dsn
contendra un string que es el nombre con el que hemos configurado nuestro dsn dentro del archivo [file]php.ini[/file] por ejemplo:
$dns = "midsn"php.ini
pdo.dsn.midsn = "mysql:host=localhost;dbname=nombre_de_la_base_de_datos"
$username
– el nombre de usuario que utilizara la base de datos
$password
– el password del usuario que utilizara la base de datos.
$options
-(opcional) es utilizada para especificar opciones de conexión, estas opciones pueden ser las de setAttribute como también pueden ser las especificas de alguno de los drivers.
$ruta_ca = "/ruta/a/tu/archivo/ca.pem"; $options = [ PDO::MYSQL_ATTR_SSL_CA => $ruta_ca, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // Otras opciones específicas de MySQL pueden ir aquí ];
Retorno
Object
– devolverá un objeto de la clase PDO.
errorCode
obtiene el SQLSTATE asociado a la última operación (consulta realizada) que ha sido manejada por el database handle. En definitiva, es el código que devuelve el DBMS que estemos utilizando, estos códigos cumplen lo siguiente:
- «S» denotes «Success» (class 00),
- «W» denotes «Warning» (class 01),
- «N» denotes «No data» (class 02)
- «X» denotes «Exception» (all other classes).
Esto quiere decir que todos los que empiezan con 00 serán success, 01 – warning, 02 – nodata, cualquier número que no empiezan como los anteriores serán Excepciones.
Description / Descripciónpublic PDO::errorCode(): mixed
Retorno
string
– el sqlstate que corresponda
null
– if no operation has been run on the database handle.
errorInfo
Obtiene información extendida del error asociado con la última operación del manejador de la base de datos (DBMS), esta información será devuelta en un array
Description / Descripciónpublic PDO::errorInfo(): array
Retorno
array
– devuelve un array numérico de 3 elementos en el cual sus elementos tendrán los siguientes datos
- Código de error SQLSTATE
- Código de error específico del driver.
- Mensaje del error específico del driver.
exec
Ejecuta una sentencia SQL y devuelve el número de filas afectadas
Description / Descripciónpublic PDO::exec(string $statement): int
Parametros
$statement
– sentencia que se ejecutara.
Retorno
int
– número de columnas que han sido afectadas
getAttribute
Obtiene un atributo de conexión de base de datos
Description / Descripciónpublic PDO::getAttribute(int $attribute): mixed
Parametros
como parámetros podemos poner alguna de las siguientes constantes:
PDO::ATTR_AUTOCOMMIT
PDO::ATTR_CASE
PDO::ATTR_CLIENT_VERSION
PDO::ATTR_CONNECTION_STATUS
PDO::ATTR_DRIVER_NAME
PDO::ATTR_ERRMODE
PDO::ATTR_ORACLE_NULLS
PDO::ATTR_PERSISTENT
PDO::ATTR_PREFETCH
PDO::ATTR_SERVER_INFO
PDO::ATTR_SERVER_VERSION
PDO::ATTR_TIMEOUT
Retornos
mixed
– En caso de exito devolvera el valor del atributo.
null
– en caso de que falle.
getAvailableDrivers
Retorna un array con los drivers que podemos utilizar
Description / Descripciónpublic static PDO::getAvailableDrivers(): array
inTransaction
El método inTransaction()
se utiliza para comprobar si una transacción está actualmente activa. Esto puede ser útil en los siguientes casos:
- Para comprobar si es necesario iniciar una transacción antes de realizar una operación que requiere una transacción.
- Para comprobar si una transacción se ha completado correctamente antes de continuar con la siguiente unidad de trabajo.
public PDO::inTransaction(): bool
Las bases de datos que admiten transacción y que más se utilizan con PDO son:
- MySQL
- PostgreSQL
- Oracle
- Microsoft SQL Server
- IBM DB2
- SQLite
- Firebird
Retornos
true
– si una transacción está activa actualmente
false
– en caso de que no tenga una transacción activa
lastInsertId
Devuelve el ID de la última fila o secuencia insertada. La tabla donde se hizo la consulta debe tener una columna AUTO_INCREMENT.
Description / Descripciónpublic PDO::lastInsertId(string $name = null): string
Parametro
$name
-es el nombre de la columna que debe ser devuelta, generalmente no necesitaras este parámetro, pero puede que en algunos drivers lo necesites como puede ser el de PostgreSQL.
Retorno
string
- (caso $name no definido), el ID de la fila
- (caso en que $name es definido) último valor de la columna especificada.
IM001
-SQLSTATE, caso en que PDO no soporte esta prestación
prepare
Prepara una sentencia para su ejecución y devuelve un objeto PDOStatement
, tenga en cuenta que esta sentencia no se ejecutara, sino que estamos creando el objeto desde donde se ejecutara con el método execute() de este.
public PDO::prepare(string $statement, array $driver_options = array()): PDOStatement
Parámetros
$statement
– una sentencia SQL o consulta.
$driver_options
– este parámetro es opcional, en algunas ocasiones es mejor realizar una array con las opciones para el driver. Por ejemplo PDO::ATTR_CURSOR
puedes ver más en https://www.php.net/manual/en/pdo.constants.php
Retornos
PDOStatement
– en caso de que se tenga éxito al ejecutar el método
false
– si ha habido un fallo, también puede devolver un PDOException
query
Ejecuta una sentencia SQL, devolviendo un conjunto de resultados como un objeto PDOStatement
Description / Descripciónpublic PDO::query( string $query, ?int $fetchMode = null ): PDOStatement|false public PDO::query( string $query, ?int $fetchMode = PDO::FETCH_COLUMN, int $colno ): PDOStatement|false public PDO::query( string $query, ?int $fetchMode = PDO::FETCH_CLASS, string $classname, array $constructorArgs ): PDOStatement|false public PDO::query(string $query, ?int $fetchMode = PDO::FETCH_INTO, object $object): PDOStatement|false
Si nuestra consulta tiene variables (placeholders), se recomienda el uso del método prepare en vez de query. Esto se debe a que prepare protege contra ataques de SQL injection.
En otras palabras query nos servira para crear consultas SELECT en nuestra base de datos, algunas personas tambien utilizan este metodo para hacer SELECT incluso teniendo placeholder pero debe de tener en cuenta el uso de quote en conjunto sino podria terminar teniendo un ataque de SQLinjection y aun asi este no brinda una seguridad absoluta
Parámetros
$query
– (string) la sentencia que será ejecutada
$fetchMode
– utilizará él por defecto que eligieras antes, en caso de tener que definir el fetchMode tienes los fetchmode que se encuentran en https://www.php.net/manual/en/pdo.constants.php
Retornos
PDOStatement
– en caso de éxito
false
– en caso de fallo
quote
le hace un entrecomillado a un string para el uso en una consulta o sentencia SQL
Description / Descripciónpublic PDO::quote(string $string, int $type = PDO::PARAM_STR): string|false
Parámetros
$string
– el string que será envuelto entre comillas
$type
– el parámetro type
del método quote()
de PDO en PHP especifica el tipo de datos de la cadena de entrada. Esto afecta a la forma en que se escapan los caracteres especiales en la cadena.
Los valores posibles para el parámetro type
son:
PDO::PARAM_STR
: La cadena se escapa como una cadena. Esto es el valor predeterminado.PDO::PARAM_INT
: La cadena se convierte en un número entero.PDO::PARAM_FLOAT
: La cadena se convierte en un número flotante.PDO::PARAM_BOOL
: La cadena se convierte en un valor booleano.PDO::PARAM_NULL
: La cadena se establece en NULL.PDO::PARAM_LOB
: La cadena se escapa como un objeto BLOB o CLOB.
Retornos
string
– Retorna un string entrecomillado que es seguro para pasar a una sentencia SQL
false
– en caso de que el driver no soporte en entrecomillado de esta manera,
setAttribute
Establece un atributo en el manejador de la base de datos. Algunos de los atributos genéricos disponibles están listados a continuación; algunos drivers pueden hacer uso de atributos adicionales específicos.
Description / Descripciónpublic PDO::setAttribute(int $attribute, mixed $value): bool
Parametros
PDO::ATTR_CASE
: Fuerza a los nombres de columnas a una capitalización específica.
Sus posibles valores son:
PDO::CASE_LOWER
: Fuerza a los nombres de columnas a minúsculas.PDO::CASE_NATURAL
: Deja los nombres de columnas como son devueltas por el driver de la base de datos.PDO::CASE_UPPER
: Fuerza a los nombres de columnas a mayúsculas.
PDO::ATTR_ERRMODE
: Reporte de errores.
PDO::ERRMODE_SILENT
: Establece los códigos de error.PDO::ERRMODE_WARNING
: Eleva E_WARNING.PDO::ERRMODE_EXCEPTION
: Lanza exceptions.
PDO::ATTR_ORACLE_NULLS
(disponible para todos los drivers, no sólo Oracle): Conversión de NULL y cadenas vacías.
PDO::NULL_NATURAL
: Sin conversión.PDO::NULL_EMPTY_STRING
: Las cadenas vacías son convertidas anull
.PDO::NULL_TO_STRING
: NULL se convierte a cadenas vacías.
PDO::ATTR_STRINGIFY_FETCHES
: Convierte los valores numéricos a cadenas cuando se buscan. sus posibles valores son : true
o false
PDO::ATTR_STATEMENT_CLASS
: Establece la clase de sentencia proporcionada por el usuario derivada de PDOStatement. No puede ser usado con instancias PDO persistentes. Requiere array(string classname, array(mixed constructor_args))
.
PDO::ATTR_TIMEOUT
: Especifica la duración del tiempo de espera en segundos.
No todos los drivers soportan esta opción y su significado difiere entre drivers
PDO::ATTR_AUTOCOMMIT
(disponible en OCI, Firebird and MySQL): Esto sirve para hacer autocommit en cada declaración sus posibles valores son true o false
PDO::ATTR_EMULATE_PREPARES
habilita o des habilita el uso de emulacion de sentencias preparadas(prepared staements)
true
– habilita la emulacion de prepared statements.
false
– deshabilita la emulacion tratando de usar los prepared statements nativos
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY
(available in MySQL): Use buffered queries.
Buffered Query (Consulta almacenada en búfer): Significa que todos los resultados se recuperan de la base de datos y se almacenan en memoria antes de que tu script comience a procesarlos. Esto permite un acceso más fácil y múltiples pasadas a través de los resultados, pero puede consumir más memoria, especialmente si los conjuntos de resultados son grandes.
Unbuffered Query (Consulta no almacenada en búfer): Significa que los resultados se leen a medida que tu script avanza, lo que puede ser más eficiente en cuanto a memoria, pero puede tener limitaciones en términos de manipulación de datos y múltiples pasadas a través de los resultados.
sus valores pueden ser true o false
PDO::ATTR_DEFAULT_FETCH_MODE
: Set default fetch mode.
sus posibles valores puedes verlos en https://www.php.net/manual/es/pdostatement.fetch.php
PDO::FETCH_ASSOC
– Devuelve un array asociativo con los nombres de las columnas como claves. Este es el valor predeterminado.PDO::FETCH_NUM
– Devuelve un array numérico con las columnas numeradas.PDO::FETCH_BOTH
– Devuelve un array asociativo y numérico con las columnas.PDO::FETCH_OBJ
– Devuelve un objeto con las columnas como propiedades.PDO::FETCH_LAZY
– Devuelve un objeto con las columnas como propiedades, pero solo carga los valores cuando se accede a ellos.
Retornos
true
en caso de éxito.
false
en caso de error.
Transacciones
Hago una separación aquí, ya que creo que beginTransaction, commit y rollback forman parte de una misma acción
Tenga en cuenta que el hacer la transacción tiene sentido cuando tenemos varias sentencias que dependen de las otras, no tendría demasiado sentido hacer una transacción para una sola sentencia
beginTransaction
inicia una transacción y desactiva el modo autocommit
Description / Descripciónpublic PDO::beginTransaction(): boolSintaxis / Sintax
//tenga en cuenta que no estamos chequeando si se conectio $pdo_connection = new PDO($dsn, $usuario, $contraseña); $pdo_connection->beginTransaction();
Retornos
true
en caso de éxito
false
en caso de error.
commit
realiza la transacción
Description / Descripciónpublic PDO::commit(): boolSintaxis / Sintax
$pdo_connection->beginTransaction();
Retornos
true
en caso de éxito
false
en caso de error.
rollBack
revierte una transacción
Description / Descripciónpublic PDO::rollBack(): boolSintaxis / Sintax
$pdo_connection->rollBack();
Retornos
true
en caso de éxito
false
en caso de error.
Veamos un ejemplo de transacciones
Ejemplo de una transaccion en php// Conectamos a la base de datos $pdo = new PDO("mysql:host=localhost;dbname=mi_base_de_datos", "manolo", "my_password"); // Creamos la transacción $pdo->beginTransaction(); // Preparamos las consultas $consulta_actualizar = $pdo->prepare( "UPDATE productos SET precio = :precio WHERE id = :id" ); $consulta_eliminar = $pdo->prepare( "DELETE FROM productos WHERE id = :id" ); // Ejecutamos las consultas try { $consulta_actualizar->execute(["precio" => 100, "id" => 1]); $consulta_eliminar->execute(["id" => 2]); } catch (PDOException $e) { // La transacción se ha fallado, por lo que la revertimos $pdo->rollBack(); // Imprimimos el error echo $e->getMessage(); } // Commit de la transacción $pdo->commit();
En las transacciones de PDO no tenemos uan forma directa de hacer un savepoint o un rollBack a este pero si podriamos utilizar exec para ello recuerde que con exec podemos ejecutar codigo SQL por tanto
$pdo->exec('SAVEPOINT my_savepoint');
y el rollback a ese savepoint deberian funcionar sin problemas
$pdo->exec('ROLLBACK TO my_savepoint');
veamos un ejemplo
try { $pdo->beginTransaction(); // Tu código SQL preparado aquí $stmt = $pdo->prepare("INSERT INTO tu_tabla (columna1, columna2) VALUES (?, ?)"); $valor1 = 'valor1'; $valor2 = 'valor2'; $stmt->bindParam(1, $valor1); $stmt->bindParam(2, $valor2); $stmt->execute(); // Usar exec para crear un savepoint $pdo->exec('SAVEPOINT my_savepoint'); // Otro código SQL preparado aquí $stmt = $pdo->prepare("UPDATE tu_tabla SET columna1 = ? WHERE columna2 = ?"); $nuevoValor1 = 'nuevo_valor1'; $condicionColumna2 = 'condicion'; $stmt->bindParam(1, $nuevoValor1); $stmt->bindParam(2, $condicionColumna2); $stmt->execute(); // Si todo está bien, confirmar la transacción $pdo->commit(); } catch (Exception $e) { // Si hay un error, puedes hacer un rollback hasta el savepoint $pdo->exec('ROLLBACK TO my_savepoint'); // Manejar el error de alguna manera }
Recomiendo el uso de
prepare
en vez de realizar unexec
, enexec
deberemos de hacerle un escapado a los datos apropiado, el cual lo podría hacer con el métodoquote
esto también se debe de hacer conprepare
aunque este último es mucho más seguro que unexec
.También con este método tenemos que tener en cuenta que nos puede devolver
0
que en algún caso es tratado comofalse
, por lo tanto, deberemos de utilizar el operador===