PHP PDO - prepare si execute

Cu metodele exec() si query() se executa imediat comenzile SQL adaugate in ele. Cu PDO e posibil sa fie pregatita o interogare SQL pentru executie fara ca sa fie transmisa imediat, pentru aceasta se foloseste metoda prepare().
prepare() preia ca argument o declaratie SQL si returneaza un obiect PDOStatement. Acest obiect are o metoda execute() prin care se executa declaratia SQL cand se doreste acest lucru, returneaza TRUE sau FALSE in caz de eroare. Sintaxa generala de aplicare este:
                $obj = $obiectPDO->prepare("Interogare SQL");
                $obj->execute(Array);
- La "Interogare SQL" se poate aplica orice instructiune pt. SQL: INSERT, SELECT, UPDATE, DELETE.
- Argumentul Array de la execute() e optional, acesta reprezinta un Array cu parametri ce corespund declaratiei SQL de la prepare(), si valorile care vor fi transmise la MySQL.


• In exemplele prezentate in aceasta lectie se foloseste tabelul "sites", creat si utilizat in lectiile anterioare, care arata astfel:
| id | | nume                         | | categorie         | | adresa                                          |
------------------------------------------------------------------------------------------------------------
| 1 | | Cursuri - Tutoriale    | | educatie          | | www.marplo.net                      |
| 2 | | Curs PHP-MySQL      | | programare    | | www.marplo.net/php-mysql |
| 3 | | Cursuri Engleza        | | limbi straine    | | www.marplo.net/engleza     |

Iata explicat mai bine printr-un exemplu cum se aplica sintaxa de mai sus intr-un script PHP cu PDO. Acesta va defini cu "prepare()" o comanda SQL prin care va selecta din tabel randurile in functie de valorile adaugate prin "execute()".
<?php
// Datele de conectare (adresa_server, baza_de_date, nume si parola)
$hostdb = 'localhost';
$namedb = 'teste';
$userdb = 'username';
$passdb = 'password';

try {
  // Conectare si creare obiect PDO
  $dbh = new PDO("mysql:host=$hostdb; dbname=$namedb", $userdb, $passdb);
  $dbh->exec("SET CHARACTER SET utf8");      // Setare encoding caractere UTF-8

  // Definire comanda SQL care va fi aplicata in metoda prepare()
  $sql = "SELECT `nume`, `adresa` FROM `sites` WHERE `id`= :id OR `categorie`= :categorie";
  $prep = $dbh->prepare($sql);        // Interogarea e pregatita si stocata in $prep

  // Variabila Array cu valori ce trebuie adaugate in interogarea SQL pregatita (pt. ':id' si ':categorie')
  $ar_val = array('id'=>2, 'categorie'=>'educatie');

  // Daca se executa cu succes interogarea, folosind execute() si valorile din $ar_val
  if($prep->execute($ar_val)) {
    // Parcurge si afiseaza randurile obtinute
    while($row = $prep->fetch()) echo $row['nume'].' - '.$row['adresa'].'<br />';
  }

     /* Se executa inca o selectare, cu alte valori, aplicata aceleiasi declaratii SQL */
   echo 'Select-ul 2<br />';

  // Variabila Array cu valori ce trebuie adaugate in interogarea SQL pregatita (pt. ':id' si ':categorie')
  $ar_val = array('id'=>8, 'categorie'=>'limbi straine');

  // Daca se executa interogarea, folosind execute() si valorile din $ar_val
  if($prep->execute($ar_val)) {
    // Parcurge si afiseaza randurile obtinute
    while($row = $prep->fetch()) echo $row['nume'].' - '.$row['adresa'].'<br />';
  }

  $dbh = null;        // Deconectare
}
catch(PDOException $e) {
  echo $e->getMessage();
}
?>
- In expresia $sql = "SELECT `nume`, `adresa` FROM `sites` WHERE `id`= :id OR `categorie`= :categorie";, ":id" si ":categorie" sunt parametri pentru valorile care vor fi preluate din Array, de la elementele cu aceeasi denumire la chei ('id' si 'categorie'). Datorita acestei notatii se poate folosi aceeasi comanda SQL pregatita, cu valori diferite.
- Observati cat de usor se pot efectua mai multe interogari la baza de date, folosind aceeasi declaratie SQL, doar prin apelarea lui "execute()" cu valorile dorite.
Script-ul va afisa:
Cursuri - Tutoriale - www.marplo.net
Curs PHP-MySQL - www.marplo.net/php-mysql
Select-ul 2
Cursuri Engleza - www.marplo.net/engleza

In declaratia SQL pregatita, in loc de sintaxa :nume pentru locul valorilor se poate folosi caracterul ?, dar in acest caz, Array-ul cu valorile trebuie sa fie secvential (adica cu chei numere incepand de la 0), valorile vor fi preluate si adaugate la SQL in ordinea lor.
        De exemplu:
                $sql = "SELECT `nume`, `adresa` FROM `sites` WHERE `id`=? OR `categorie`=?";
                $prep = $dbh->prepare($sql);
                $prep->execute(array(2, 'programare'));

bindValue si bindParam

Un alt mod de a transmite valori la o interogare SQL pregatita cu "prepare()" este utilizarea metodei bindValue() sau bindParam().
Utilizarea acestor metode in loc de Array are avantajul ca ofera un control mai bun asupra valorilor transmise, putand fi specificate prin atributele lor tipul de date si chiar numarul de caractere ce-l va avea valoarea transmisa. Ele se aplica la obiectul PDOStatement obtinut cu "prepare()".
Diferenta dintre bindValue si bindParam este:


    • La bindValue se adauga direct valoarea si optional se poate specifica numarul de caractere ce vor fi transmise. Sintaxa generala este:
                bindValue(paramSQL, valoare, tip, nr_caractere)
- paramSQL este parametrul din declaratia SQL, specificat cu :nume, intre ghilimele. Daca e folosit semnul-intrebarii ?, la paramSQL se adauga numarul de ordine (incepand cu 1) al acelui parametru.
- tip e optional, la el se precifica o constanta prin care se defineste tipul de date care trebuie transmis: PDO::PARAM_INT pt. numere intregi, PDO::PARAM_STR pentru siruri.
- La nr_caractere se adauga, optional, numarul de caractere ce va fi transmis.
    De exemplu:
 $sql = "SELECT `nume`, `adresa` FROM `sites` WHERE `id`= :id OR `categorie`= :categorie";
 $prep = $dbh->prepare($sql);

 $prep->bindValue(':id', 2, PDO::PARAM_INT);          // Transmite valoarea 2 la coloana "id"
 $prep->bindValue(':categorie', 'programare', PDO::PARAM_STR, 10);          // Transmite valoarea "programare" la coloana "categorie"

 $prep->execute();


    • La bindParam se adauga valoarea prin variabile. Sintaxa generala este:
                bindParam(paramSQL, $var_val, tip)
- paramSQL este parametrul din declaratia SQL, specificat cu :nume, intre ghilimele. Daca e folosit semnul-intrebarii ?, la paramSQL se adauga numarul de ordine (incepand cu 1) al acelui parametru.
- $var_val e o variabila in care e stocata valoarea.
- tip e optional, la el se precifica o constanta prin care se defineste tipul de date care trebuie transmis: PDO::PARAM_INT pt. numere intregi, PDO::PARAM_STR pentru siruri.
    De exemplu:
 $sql = "SELECT `nume`, `adresa` FROM `sites` WHERE `id`=? OR `categorie`=?";
 $prep = $dbh->prepare($sql);

 $id = 2;
 $cat = 'programare';

 $prep->bindParam(1, $id, PDO::PARAM_INT);        // Transmite valoarea din variabila $id la coloana de la primul ? (adica "id")
 $prep->bindParam(2, $cat, PDO::PARAM_STR);       // Transmite valoarea din variabila $cat la coloana de la al doilea ? (categorie)

 $prep->execute();

• Iata si un exemplu practic cu aceste doua metode, aplicat la tabelul "sites". Se adauga doua randuri in tabel, unul dupa altul; primul folosind bindValue(), iar al doilea cu bindParam()
<?php
// Datele de conectare (adresa_server, baza_de_date, nume si parola)
$hostdb = 'localhost';
$namedb = 'teste';
$userdb = 'username';
$passdb = 'password';

try {
  // Conectare si creare obiect PDO
  $dbh = new PDO("mysql:host=$hostdb; dbname=$namedb", $userdb, $passdb);
  $dbh->exec("SET CHARACTER SET utf8");      // Setare encoding caractere UTF-8

  // Definire comanda SQL care va fi aplicata in metoda prepare()
  $sql = "INSERT INTO `sites` (`nume`, `categorie`, `adresa`) VALUES (:nume, :categorie, :adresa)";
  $prep = $dbh->prepare($sql);        // Interogarea e pregatita si stocata in $prep

  // Se adauga valori cu bindValue
  $prep->bindValue(':nume', 'Curs Ajax', PDO::PARAM_STR);
  $prep->bindValue(':categorie', 'programare', PDO::PARAM_STR);
  $prep->bindValue(':adresa', 'www.marplo.net/ajax', PDO::PARAM_STR);

  // Daca datele sunt adaugate cu succes, afiseaza confirmare cu id-ul randului
  if($prep->execute()) echo 'A fost adaugat randul cu id='. $dbh->lastInsertId();

  // Se definesc variabile cu valori ce vor fi incluse cu bindParam
  $nume = 'Jocuri Flash';
  $categorie = 'jocuri';
  $adresa = 'www.marplo.net/jocuri';

  // Se includ variabilele
  $prep->bindParam(':nume', $nume, PDO::PARAM_STR);
  $prep->bindParam(':categorie', $categorie, PDO::PARAM_STR);
  $prep->bindParam(':adresa', $adresa, PDO::PARAM_STR);

  // Daca datele sunt adaugate cu succes, afiseaza confirmare cu id-ul randului
  if($prep->execute()) echo '<br />A fost adaugat randul cu id='. $dbh->lastInsertId();

  $dbh = null;        // Deconectare
}
catch(PDOException $e) {
  echo $e->getMessage();
}
?>
- In browser va afisa:
A fost adaugat randul cu id=4
A fost adaugat randul cu id=5

Utilizarea combinatiei prepare() ... execute() este adesea mai rapida decat query() / execute(). In plus, aceasta formula este utila cand trebuie folosita de mai multe ori aceeasi declaratie SQL, cu parametri diferiti.
Un alt avantaj e acela ca datele ce trebuie transmise la serverul MySQL sunt mai clar separate de comanda SQL, in plus sunt si filtrate. De exemplu, daca se transmite cu o metoda "bind" sirul "a' b' c", PDO include sirul "a\' b\' c".

• Daca interogarea SQL contine instructiunea LIKE cu un parametru, caracterul '%' trebuie adaugat la valoarea transmisa.
    De exemplu:
               // incorect
$prep = $dbh->prepare("SELECT `coloana` FROM `tabel` WHERE `coloana` LIKE %:cuvant%");
$prep->bindValue(':cuvant', 'valoare');

               // E CORECT
$prep = $dbh->prepare("SELECT `coloana` FROM `tabel` WHERE `coloana` LIKE :cuvant");
$prep->bindValue(':cuvant', '%valoare%');

- In lectia urmatoare va fi prezentat lucru cu metodele: setAttribute(), beginTransaction() si commit().
PHP PDO - Select, ... <<-- Anterior --- Urmator -->> PHP PDO - setAttribute ...

Un Test simplu in fiecare zi

HTML
CSS
JavaScript
PHP-MySQL
Engleza
Spaniola
Ce tag adauga imagine in pagina web?
<div> <img> <span>
<img src="http://coursesweb.net/imgs/webcourses.gif" width="191" height="63" alt="Courses-Web" />
Care din aceste coduri CSS afiseaza textul inclinat?
font-style: italic; text-decoration: underline; font-weight: 500;
#id {
  font-style: italic;
}
Clic pe functia jQuery care ascunde animat un element HTML.
click() hide() show()
$(document).ready(function() {
  $(".a_class").click(function(){ $(this).hide("slow"); });
});
Clic pe functia definita corect in PHP.
fname function() {} function fname() {} function $fname() {};
function fname($a, $b) {
  echo $a * $b;
}
Indicati forma pentru Prezent Perfect Continuu a verbului "to walk" (a merge).
have walked have been walking be walking
I have been walking for 5 hours.
- Merg pe jos de 5 ore.
Indicati Trecutul Nedefinit pentru verbul "ser" (a fi) la forma Yo.
será sería fui
Yo fui entrenador.
- Am fost antrenor.
PHP PDO - prepare si execute - Tutoriale PHP