Blog de programación, errores, soluciones

Chose Language:
Author: Admin/Publisher |finished | checked

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 / Synopsis
class 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ón
public 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:

dsn alias
$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ón
public 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ón
public PDO::errorInfo(): array

Retorno

array – devuelve un array numérico de 3 elementos en el cual sus elementos tendrán los siguientes datos

  1. Código de error SQLSTATE
  2. Código de error específico del driver.
  3. Mensaje del error específico del driver.

exec

Ejecuta una sentencia SQL y devuelve el número de filas afectadas

Description / Descripción
public PDO::exec(string $statement): int

Parametros

$statement – sentencia que se ejecutara.

Retorno

int – número de columnas que han sido afectadas

Recomiendo el uso de prepare en vez de realizar un exec, en exec deberemos de hacerle un escapado a los datos apropiado, el cual lo podría hacer con el método quote esto también se debe de hacer con prepare aunque este último es mucho más seguro que un exec.

También con este método tenemos que tener en cuenta que nos puede devolver 0 que en algún caso es tratado como false, por lo tanto, deberemos de utilizar el operador ===

getAttribute

Obtiene un atributo de conexión de base de datos

Description / Descripción
public 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ón
public 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.
Description / Descripción
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ón
public 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.

Description / Descripción
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ón

public 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ón
 
public 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ón
 
public 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 a null.
  • 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

volverá siempre a la emulación de las sentencias preparadas si el driver no puede hacerlo

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ón
public PDO::beginTransaction(): bool
Sintaxis / 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ón
public PDO::commit(): bool
Sintaxis / Sintax
$pdo_connection->beginTransaction();

Retornos

true en caso de éxito

false en caso de error.

rollBack

revierte una transacción

Description / Descripción
public PDO::rollBack(): bool
Sintaxis / 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
}
Category: php
Something wrong? If you found an error or mistake in the content you can contact me on Twitter | @luisg2249_luis.
Last 4 post in same category