jueves, 10 de febrero de 2011

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:

# 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.


// 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


$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:


$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:


$STH->bindParam(':name', $name);


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


$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:


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:


$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:


# 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:


# 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:


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:


$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.


$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:


$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():


$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.

No hay comentarios:

Publicar un comentario