Motivos para usar PHP con PDO siempre - reasons for development with PHP pdo always

Porque debería usar PHP’s PDO Para acceder a Bases de Datos? Parte 1

Muchos programadores aprendieron como obtener acceso a bases de datos mysql usando las extensiones mysql o mysqli.
A partir de PHP 5.1, se encuentra disponible una mejor opción. PDO (PHP Data Objects) provee métodos para preparar consulta SQL
Y trabajar con objetos que le harán mucho más productivo!

Introducción PDO
“PDO – PHP Data Objects – es una capa de acceso estandarizada que proporciona un método uniforme de acceso a múltiples bases de datos”.
No toma en cuenta para la sintaxis de base de datos específica, pero puede permitir migrar fácilmente de entre motores bases de datos y plataformas sin muchos dolores de cabeza, cambiando la cadena de conexión en la mayoría de los casos.
Este post está dirigido a personas que actualmente usan las extesiones mysql y mysqli para obtener acceso a bases de datos.

Motores de Bases de datos soportados
La extensión puede soportar cualquier base de datos para que exista escrito un driver PDO. Actualmente los controladores de bases de datos disponibles son las siguientes:

• PDO_DBLIB ( FreeTDS/Microsoft SQL Server/Sybase )
• PDO_FIREBIRD ( Firebird/Interbase 6 )
• PDO_IBM ( IBM DB2 )
• PDO_INFORMIX ( IBM Informix Dynamic Server )
• PDO_MYSQL ( MySQL 3.x/4.x/5.x )
• PDO_OCI ( Oracle Call Interface )
• PDO_ODBC ( ODBC v3 (IBM DB2, unixODBC ywin32 ODBC) )
• PDO_PGSQL ( PostgreSQL )
• PDO_SQLITE ( SQLite 3 ySQLite 2 )
• PDO_4D ( 4D )
Todos estos controladores no están necesariamente disponibles en su sistema, una forma rápida de saber con que controladores se cuenta en el sistema:
?
1
2
3
print_r(PDO::getAvailableDrivers()); 

Establecer Conexión
Diferentes bases de datos pueden tener diferentes métodos de conexión. A continuación, muestro el método para conectarse a algunos de los motores de bases de datos más populares. Observe que los tres primeros son idénticos a excepción de la conexión SQLite el cual cuenta con una sintaxis propia.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
try
  // MS SQL Server ySybase con PDO_DBLIB 
  $DBH = new PDO("mssql:host=$host;dbname=$dbname, $user, $pass"); 
  $DBH = new PDO("sybase:host=$host;dbname=$dbname, $user, $pass"); 
   
  // MySQL con PDO_MYSQL 
  $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass); 
   
  // SQLite
  $DBH = new PDO("sqlite:my/database/path/database.db"); 
catch(PDOException $e) { 
    echo $e->getMessage(); 

Por favor, tome nota del bloque try/catch, siempre debe realizar sus operaciones PDO en un try/catch, y utilizar el mecanismo de excepción pertinente, esto lo veremos en breve. Normalmente, usted sólo va a hacer una sola conexión, $DBH representa nuestra conexión a la base de datos que especifiquemos.
Usted puede cerrar cualquier conexión estableciendo la instancia del objeto en null.
?
1
2
3
4
//SQLite
$DBH = null; 

Puede obtener más información sobre las opciones específicas de base de datos y/o cadenas de conexión para otras bases de datos en PHP.net .

PDO y las Excepciones
PDO puede utilizar excepciones para controlar los errores. Puede forzar PDO en uno de los tres modos de error al establecer el atributo error mode en la conexión de su base de datos. Ésta es la sintaxis:
?
1
2
3
4
5
$DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT ); 
$DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING ); 
$DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); 

No importa el valor que se establezca en el error mode, un error de conexión siempre produce una excepción y la creación de una conexión siempre debe estar contenida en un bloque try/catch.

PDO:: ERRMODE_SILENT
Este es el modo de error por defecto. Si lo deja en este modo, se debe comprobar si hay errores. Los otros dos métodos son más ideales para la programación de SECO.

PDO:: ERRMODE_WARNING
Este modo emitirá un nivel de alerta de PHP, y permite a la programa continuar con su ejecución. Es útil en procesos de depuración.

PDO:: ERRMODE_EXCEPTION
Este es el modo sugerido en la mayoría de las situaciones. Se dispara una excepción, lo que le permite controlar los errores con gracia y ocultar los datos que puedan ayudar a alguien a realizar operaciones mal intencionadas en el sistema. Un ejemplo de tomar ventaja de las excepciones:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Conexion
try
  $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass); 
  $DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); 
   
  //Error incrustado DELECT = DELETE 
  $DBH->prepare('DELECT name FROM employee); 
catch(PDOException $e) { 
    echo "Boom!!!!."
    file_put_contents('PDOErrors.txt', $e->getMessage(), FILE_APPEND); 

Hay un error intencional en la instrucción de selección, lo que provocará una excepción. La excepción envía los detalles del error a un archivo de registro, y muestra un mensaje amistoso (o no muy claro) para el usuario.


Porque debería usar PHP’s PDO Para acceder a Bases de Datos? Parte 2

Insertar y actualización
Inserción de nuevos datos o actualizar los datos existentes es una de las operaciones de base de datos más comunes. Uso de DOP, esto es normalmente un proceso de dos pasos. Todo lo descrito en esta sección se aplica por igual tanto INSERT como para UPDATE.

Aquí un ejemplo del tipo más básico de inserción:
?
1
2
3
4
5
# STH means "Statement Handle" 
$STH = $DBH->prepare("INSERT INTO person ( first_name ) values ( 'Cathy' )"); 
$STH->execute(); 

También se puede realizar la misma operación utilizando el método exec(). En la mayoría de los casos, usted va a utilizar el método más largo para lograr tomar ventaja de declaraciones preparadas. Incluso si sólo va a utilizarla una vez, ya que las declaraciones preparadas le ayudarán a protegerse de los ataques de inyección SQL.

Sentencias preparadas
El uso de declaraciones preparadas le ayudará a protegerse de la inyección de SQL.


Una declaración preparada es una instrucción SQL precompilada que se pueden ejecutar varias veces mediante el envío sólo de datos al servidor. Tiene la ventaja adicional de establecer de forma automática los datos utilizados en los marcadores de posición asegurándonos así de un ataque de inyección SQL.
Utilice una declaración preparada mediante la inclusión de marcadores de posición (parámetros) en su instrucción SQL. Veamos 3 ejemplos: uno sin marcadores de posición, uno con marcadores de posición sin nombre, y uno con marcadores de posición con nombre.

?
1
2
3
4
5
6
7
8
9
10
// sin marcadores de posición
$STH = $DBH->("INSERT INTO person (name, addr, city) values ($name, $addr, $city)"); 
   
# usando marcadores de posición  sin nombre
$STH = $DBH->("INSERT INTO person (name, addr, city) values (?, ?, ?) ");
  
# usando marcadores de posición con nombre
$STH = $DBH->("INSERT INTO person (name, addr, city) value (:name, :addr, :city)");


Es recomendable evitar el primer método, que se utiliza aquí para la comparación. La opción de usar marcadores con nombre o sin nombre afectará la forma de configurar los datos en las instrucciones SQL.

Marcadores de posición sin nombre

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$STH->bindParam(1, $name); 
$STH->bindParam(2, $addr); 
$STH->bindParam(3, $city);  
 
$name = "Daniel" 
$addr = "1 Wicked Way"
$city = "Arlington Heights"
$STH->execute(); 
   
$name = "Steve" 
$addr = "5 Circle Drive"
$city = "Schaumburg"
$STH->execute();



Contamos con dos pasos para ejecutar nuestras sentencias SQL. En primer lugar, asignamos variables diferentes a los marcadores de posición (líneas 2-4). Luego, asignamos valores a los marcadores de posición y por ultimo ejecutamos nuestra sentencia SQL. Para ejecutar otra sentencia SQL solo será necesario cambiar los valores de las variables y ejecutar nuevamente la sentencia SQL.

¿Esto parece un poco difícil de manejar para las sentencias con una gran cantidad de parámetros? Eso es cierto. Sin embargo, si los datos se almacenan en una matriz, hay una opción más corta:

?
1
2
3
4
5
6
$data = array('Cathy', '9 Dark and Twisty Road', 'Cardiff'); 
   
$STH = $DBH->("INSERT INTO person (name, addr, city) values (?, ?, ?); 
$STH->execute($data);



Waao, Que fácil!
Los datos de la matriz se aplican a los marcadores de posición en orden secuencial. $data[0] será asignado al primer marcador de posición, $data[1],en el segundo, etc Sin embargo, si los índices de matriz no están en orden, esto no funcionará muy bien que digamos, y se tendrá que volver a indexar la matriz.

Marcadores de posición con nombre
Probablemente se podría adivinar la sintaxis, pero aquí dejo un ejemplo:

?
1
2
3
$STH->bindParam(':name', $name);


Aquí también se puede utilizar una matriz (array), pero en este caso trabaja con las matrices asociativas. Ejemplo:

?
1
2
3
4
5
6
7
$data = array( 'name' => 'Cathy', 'addr' => '9 Dark and Twisty', 'city' => 'Cardiff' ); 
   
# the shortcut! 
$STH = $DBH->("INSERT INTO person (name, addr, city) value (:name, :addr, :city)"); 
$STH->execute($data); 


No es necesario que las claves de la matriz comiencen con dos puntos, pero todo lo demás es necesario para lograr que coincidan los valores en los marcadores de posición con nombre. Si usted tiene una matriz de matrices se puede iterar sobre cada una de ellas, y simplemente ejecute su sentencia SQL con cada conjunto de datos.

Otra característica interesante de los marcadores de posición con nombre es la posibilidad de insertar objetos directamente en la base de datos, suponiendo que las propiedades del objeto coinciden con los campos con nombre. Veamos un ejemplo con un objeto y cómo añadirlo:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class person { 
    public $name
    public $addr
    public $city
   
    function __construct($n,$a,$c) { 
        $this->name = $n
        $this->addr = $a
        $this->city = $c
    
    # ... 
   
$cathy = new person('Cathy','9 Dark and Twisty','Cardiff'); 
   
$STH = $DBH->("INSERT INTO folks (name, addr, city) value (:name, :addr, :city)"); 
$STH->execute((array)$cathy); 



Se convierte el objeto en una matriz y se ejecuta la sentencia SQL, las propiedades son tratadas como claves de matriz.

Seleccionando datos

Los datos se obtienen a través del metodo -> fetch (), el cual es un método de nuestro identificador de instrucción. Antes de llamar a fecth(), lo mejor es decirle PDO cómo quieres obtener los datos. Para lo cual se cuenta con las siguientes opciones:
PDO:: FETCH_ASSOC: devuelve una matriz indexada por nombre de columna
PDO:: FETCH_BOTH (por defecto): devuelve una matriz indexada por nombre y número de columna
PDO:: FETCH_BOUND: Asigna los valores de las columnas a las variables definidas con el metodo ->bindColumn()
PDO:: FETCH_CLASS: Asigna los valores de las columnas a las propiedades de la clase. Se crearan las propiedades si no existen
PDO:: FETCH_INTO: Actualiza una instancia existente de la clase especificada.
PDO:: FETCH_LAZY : Combina PDO:: FETCH_BOTH/DOP:: FETCH_OBJ, creando los objetos y las variables para su uso.
PDO:: FETCH_NUM: devuelve una matriz indexada por número de columna.
PDO:: FETCH_OBJ: devuelve un objeto anónimo con nombres de propiedades que corresponden a los nombres de columna.

En realidad, hay tres que cubren la mayoría de las situaciones: FETCH_ASSOC, FETCH_CLASS y FETCH_OBJ. La sintaxis que se utiliza con el fin de establecer el método fecth() es la siguiente:

?
1
2
3
$STH->setFetchMode(PDO::FETCH_ASSOC);


FETCH_ASSOC

Este crea una matriz asociativa, indexada por nombre de columna. Esto debería ser muy familiar para cualquiera que haya usado las extensiones mysql/mysqli. Veamos un ejemplo de selección de datos con este método:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
# creamos nuestra sentencia SQL
$STH = $DBH->query('SELECT name, addr, city from person); 
   
# configuramos el modo deseado
$STH->setFetchMode(PDO::FETCH_ASSOC); 
   
while($row = $STH->fetch()) { 
    echo $row['name'] . "\n"
    echo $row['addr'] . "\n"
    echo $row['city'] . "\n"


El bucle while se ejecuta hasta terminar de escribir en pantalla el resultado obtenido.

FETCH_OBJ

Este crea un objeto para cada fila de datos captados. Ejemplo:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# creamos nuestra sentencia SQL
$STH = $DBH->query('SELECT name, addr, city from person); 
   
# configuramos el modo deseado
$STH->setFetchMode(PDO::FETCH_OBJ); 
   
# mostramos el resultado
while($row = $STH->fetch()) { 
    echo $row->name . "\n"
    echo $row->addr . "\n"
    echo $row->city . "\n"
}


FETCH_CLASS
Las propiedades del objeto se establecen antes que el constructor sea llamado. Esto es importante.


Este método le permite recuperar los datos directamente en una clase especificada. Cuando se utiliza FETCH_CLASS, las propiedades de su objeto se establecen antes de llamar al constructor. Las propiedades que no existan como según las columnas obtenidas se crearan automáticamente.
Esto significa que si sus datos necesitan cualquier transformación después de salir de la base de datos, se pueden hacer automáticamente por su objeto, ya que cada objeto es creado.
Ejemplo, imagine una situación en la que la dirección tiene que ser parcialmente protegida por cada registro. Podemos hacer esto operando con la propiedad en el constructor. veamos:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
class secret_person { 
    public $name
    public $addr
    public $city
    public $other_data
   
    function __construct($other = '') { 
        $this->address = preg_replace('/[a-z]/', 'x', $this->address); 
        $this->other_data = $other
    


Como los datos se traen en esta clase, la dirección tiene caracteres entre a-z en minúscula y la sustituiremos por la letra x. Ahora, al momento de usar la clase todas las transformaciones curren de forma transparente:

?
1
2
3
4
5
6
7
8
$STH = $DBH->query('SELECT name, addr, city from person); 
$STH->setFetchMode(PDO::FETCH_CLASS, 'secret_person'); 
   
while($obj = $STH->fetch()) { 
    echo $obj->addr; 
}


Si la dirección es “5 Bronds”, se obtendrá “5 Bxxxxx”. Por supuesto, puede haber situaciones en las que desea que el constructor se llame antes de asignar los datos. PDO ofrece una solución ante esto también.

?
1
2
3
$STH->setFetchMode(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'secret_person');  


Ahora, cuando se repita el ejemplo anterior con este modo establecido (PDO:: FETCH_PROPS_LATE) La dirección no se oculta, ya que el constructor se llama y las propiedades ya fueron asignadas.
Por último, si usted necesita pasar argumentos al constructor durante la obtención de datos en objetos con PDO, use el siguiente modo:

?
1
2
3
$STH->setFetchMode(PDO::FETCH_CLASS, 'secret_person', array('stuff')); 


Si usted necesita para pasar datos de forma dinámica al constructor para cada objeto, puede establecer el modo al momento de ejecutar fecth():

?
1
2
3
4
5
6
$i = 0; 
while($rowObj $STH->fetch(PDO::FETCH_CLASS, 'secret_person', array($i))) { 
    $i++ 
}



Conclusión
Espero que estos dos artículos ayuden a muchos programadores a cambiarse de las extensiones mysql y mysqli.

CommentFB