Coduri Php Pdo pentru rețeaua socială. De ce ar trebui să utilizați PDO pentru a lucra cu o bază de date

PDO (PHP Data Objects) este o extensie pentru PHP care oferă o interfață simplă pentru accesarea diferitelor baze de date. Pentru a spune foarte simplu și pe scurt, folosind PDO în PHP vă conectați la baze de date de diferite tipuri.

În acest tutorial ne vom conecta la o bază de date MySQL, deoarece este cea mai comună bază de date.

Conectarea la baza de date

Trebuie să știți că serverul de baze de date are un nume, iar utilizatorii se pot conecta și la el, adică pentru a se conecta trebuie să se folosească un login și o parolă.

Un exemplu despre cum ne putem conecta la o bază de date:

$db = PDO nou ("mysql:host=$host;dbname=$db", $user, $pass);

Cred că dacă ești interesat de PDO, atunci cunoștințele tale sunt suficiente și nu trebuie să ți se explice această sintaxă.

Deci avem un obiect de conexiune pentru a accesa baza de date.

Tratarea excepțiilor

Când utilizați PDO, vă recomand să detectați erorile de conexiune folosind constructul try(...)catch(...). Iată un exemplu de astfel de cod:

Încercați ( $db = new PDO("myql:host=$host;dbname=$dbname", $user, $pass); ) catch(PDOException $e) ( echo "Aveți o eroare: ".$e-> getMessage()."
"; echo "La linie: ".$e->getLine(); )

Există opinii diferite cu privire la gestionarea erorilor, de exemplu, nu toată lumea recomandă utilizarea întotdeauna a constructului try(...)catch(...). Chestia este că oricum PHP va imprima un mesaj de eroare pe ecran, deci acest cod este redundant. Deși dacă doriți, de exemplu, să anulați o tranzacție, atunci această construcție vă va fi utilă, dar mai multe despre asta mai jos.

Preluarea datelor din baza de date folosind PDO, metoda de interogare

Pentru a selecta din baza de date, folosim metoda de interogare, căreia îi trecem un șir de interogare SQL.

$db->query("SELECT * FROM utilizatori");

Nu uitați că această sintaxă va funcționa pentru toate tipurile de baze de date.

De asemenea, nu uitați de securitatea datelor transmise în interogările SQL. PDO are un analog al funcției mysql_real_escape_string() - metoda citatului.

$login = $db->quote($_POST["login"]); $sql = "SELECT * FROM utilizatori WHERE login = $login"; $rezultat = $db->interogare($sql);

Procesarea rezultatelor, metodele FETCH și FETCHALL.

Acum trebuie să convertim rezultatul din variabila $res într-o matrice. Acest lucru se face folosind metoda FETCH, căreia i se trece o constantă.

$res = $db->query($sql); $rezultat = $res->FETCH(PDO::FETCH_NUM); // numerotat $rezultat = $res->FETCH(PDO::FETCH_ASSOC); // asociativ $rezultat = $res->FETCH(PDO::FETCH_BOTH); // asociativ și numerotat împreună $rezultat = $res->FETCH(PDO::FETCH_OBJ); // tip obiect $rezultat = $res->FETCH(PDO::FETCH_LAZY); // toate tipurile deodată

Evident, constanta FETCH_LAZY încetinește scriptul, așa că este indicat să nu o folosești.

Metoda FETCH returnează o înregistrare din rezultat. Dacă doriți să preluați toate înregistrările, trebuie să utilizați metoda FETCHALL. Ulterior, rezultatul obținut ca urmare a utilizării FETCHALL este procesat într-o buclă foreach, așa cum se arată în exemplu:

$interogare = $db->query("SELECT * FROM utilizatori"); $rezultat = $interogare->FETCHALL(PDO::FETCH_ASSOC); foreach($rezultat ca $arry) ( echo $arry["nume"] . "
"; }

FETCH_CLASS constantă

Constanta FETCH_CLASS necesită o explicație specială, vă permite să completați o clasă pre-creată cu date din rezultatul unei interogări de bază de date.

Să ne uităm la un exemplu folosind constanta FETCH_CLASS:

Utilizator de clasă ( public $login; public $pass; funcția publică showInfo() ( echo "
" . $acest->pass."
" . " : " . $this->login ."
"; ) ) $rezultat = $stmt->FETCHALL(PDO::FETCH_CLASS, "Utilizator"); foreach($rezultat ca $user) ( $user->showInfo(); )

Nu uitați de o regulă importantă - numele proprietăților din clasa creată trebuie să fie aceleași cu numele câmpurilor din baza de date.

Expresii pregătite

Expresiile pregătite trebuie utilizate dacă interogarea dvs. SQL conține variabile.

Declarațiile pregătite PDO sunt principalul motiv pentru a utiliza PHP Data Objects, deoarece sunt singura modalitate sigură de a executa interogări SQL care conțin variabile create de utilizator.

Expresiile pregătite în PDO sunt o interogare SQL obișnuită în care o variabilă este înlocuită cu un marker special - un substituent.

Substituenți numiți

Mai întâi, să ne uităm la substituentul numit, sintaxa acestuia este de exemplu: :email.

Să ne uităm la un exemplu de interogare INSERT folosind substituenți.

$stmt = $db->prepare("INSERT INTO mesaje (e-mail, mesaj) VALORI (:email, :message)");

În acest exemplu, în loc de variabile din cerere, am folosit doi substituenți (:email, :message)").

$stmt = $db->prepare("INSERT INTO mesaje (e-mail, mesaj) VALORI (:email, :message)"); $stmt->bindParam(":email", $email); $stmt->bindParam(":mesaj", mesaj); $email = "E-mail nr. 1"; $message = "Un text al mesajului"; $stmt->execute(); $email = "E-mail nr. 2"; $message = "Un text al mesajului"; $stmt->execute();

Vă rugăm să rețineți că pentru a pregăti o interogare SQL, o scriem în metoda prepare(). Apoi, pentru a indica ce substituent să lege ce variabilă, folosim metoda bindParam(). Pentru a executa o interogare SQL, apelăm metoda execute().

Deci, încă o dată, succesiunea de lucru cu expresii pregătite pas cu pas:

  1. Atribuim rezultatul executării metodei prepare() variabilei $stmt.
  2. Folosind metoda bindParam(), legăm variabile și substituenți.
  3. Atribuirea de valori variabilelor.
  4. Folosind metoda execute(), executăm o interogare în baza de date.

Această sintaxă poate fi scrisă

$stmt = prepare("SELECT numele de la utilizatori WHERE email = :email"); $stmt->execute(array("email" => $email));

Se poate observa că un tablou trebuie trecut la metoda execute(), în care cheile trebuie să se potrivească cu numele substituenților.

Apropo, metoda bindParam() are un sinonim bindValue() .

Substituenți fără nume

Acum să ne uităm la lucrul cu substituenți fără nume.

$stmt = prepare("SELECT numele de la utilizatori WHERE email = ?") $stmt->execute(array($email));

În această sintaxă, în loc de înregistrarea substituent:nume, este indicată o altă formă a înregistrării sale - un semn de întrebare:? .

Aici valorile matricei $email vor fi atribuite substituenților unul câte unul:? , dar în exemplul nostru există un singur substituent.

Iată un alt exemplu de utilizare a substituenților fără nume, folosind metoda bindParam():

$stmt = $db->prepare("INSERT INTO articles (titlu, text) VALUES (?, ?)"); $stmt->bindParam(1, $email); $stmt->bindParam(2, $mesaj); $email = "E-mail nr. 1"; $message = "Un text al mesajului"; $stmt->execute(); $email = "E-mail nr. 2"; $message = "Un text al mesajului"; $stmt->execute();

Inserarea într-o bază de date, metoda exec().

Dacă vrem să scriem ceva în baza de date, atunci putem folosi și metoda PDO::exec().

$sql = "INSERT INTO (login, parola) VALUES ($login, $parola)"; $rezultat = $db->exec($sql);

Dacă această interogare este executată, variabila $result va conține numărul de rânduri afectate în tabel.

PDO::exec() execută interogări INSERT, dar nu poate prelua date din baza de date, aceasta este gestionată de metoda PDO::query(). PDO::exec() rulează doar interogarea SQL și returnează numărul de rânduri implicate în timpul execuției sale, nu returnează rezultatul instrucțiunii SELECT.

PDO lucrează cu baze de date. Dacă nu puteți lucra cu un anumit tip de bază de date, accesați php.ini și căutați linii care încep cu extension=php_pdo_(numele bazei de date) și anulați-le comentariile.

PHP pentru începători: Funcții de apel invers, Lecția 34! https://www.youtube.com/watch?v=2NwLHXUoXcw https://www.youtube.com/watch?v=GMzI6jR_bE4 https://www.youtube.com/watch?v=gFJsBQIqpto PHP lecția 9 Recursiune https ://www.youtube.com/watch?v=gLAeJcKkd6c http://php.net/manual/ru/mysqli-result.fetch-array.php /* ștergeți rezultatele eșantionării */ mysqli_free_result($result); /* închide conexiunea */ mysqli_close($link); http://myrusakov.ru/sql-osnovy.html Articol bun: https://ru.wikipedia.org/wiki/Join_(SQL) OOP PHP. Extension Tools Capitolul „Extension Tools” din cartea lui Matt Zandstra „PHP. Objects, Templates and Programming Techniques”. https://www.youtube.com/watch?v=6L2bxtTBCRo

http://phpfaq.ru/pdo#intro - există un articol bun aici. Există informații importante despre excepții.

Este descris mai simplu: http://myrusakov.ru/php-data-objects.html

Video: https://www.youtube.com/watch?v=ACUiBH5qV0U&list=PLr_acfJGVcirEijJXmKxj8QGkWkKb-Tj-&nohtml5=False












PDO are propria sa metodă inteligentă de conectare numită . În plus, în timpul conexiunii puteți seta o mulțime de opțiuni, dintre care unele sunt extrem de utile. O listă completă poate fi găsită, dar doar câteva sunt importante.

Exemplu de conexiune corectă:

$gazdă = "127.0.0.1" ;
$db = "test" ;
$user = "rădăcină" ;
$trece = "" ;
$charset = "utf8" ;

$dsn = "mysql:host= $host ;dbname= $db ;charset= $charset " ;
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = PDO nou ($dsn, $user, $pass, $opt);

Ce se întâmplă aici?

$dsn specifică tipul de bază de date cu care vom lucra (mysql), gazdă, numele bazei de date și setul de caractere.
- urmat de nume de utilizator și parolă
- după care este specificată o serie de opțiuni, despre care nu este scris în niciunul dintre manuale.

În ciuda faptului că această matrice este un lucru extrem de util, așa cum am menționat mai sus. Cel mai important lucru este că modul de eroare ar trebui setat numai sub formă de excepții.
- În primul rând, deoarece în toate celelalte moduri PDO nu raportează nimic inteligibil despre eroare,
- în al doilea rând, deoarece excepția conține întotdeauna o urmă de stivă de neînlocuit,
- în al treilea rând, excepțiile sunt extrem de convenabil de gestionat.

În plus, este foarte convenabil să setați FETCH_MODE în mod implicit, pentru a nu-l scrie în FIECARE solicitare, așa cum le place hamsterii harnici.
Tot aici puteți seta modul pconnect, emularea expresiilor pregătite și multe alte cuvinte înfricoșătoare.

Ca rezultat, obținem variabila $pdo, cu care lucrăm pe parcursul întregului script.

Puteți folosi două metode pentru a executa interogări.
Dacă nu sunt transmise variabile la cerere, atunci puteți utiliza funcția query(). Acesta va executa cererea și va returna un obiect special - instrucțiunea PDO. Foarte aproximativ, o puteți compara cu resursa mysql, care a fost returnată de mysql_query(). Puteți obține date de la acest obiect fie în mod tradițional, prin while sau prin foreach(). De asemenea, puteți cere să returnați datele primite într-un format special, care este discutat mai jos.
$stmt = $pdo -> interogare ("SELECT numele de la utilizatori");
while ($row = $stmt -> fetch())
{
}

Dacă cel puțin o variabilă este transmisă cererii, atunci această solicitare trebuie executată numai prin expresii pregătite. Ce este? Aceasta este o interogare SQL obișnuită, în care este plasat un marker special în loc de o variabilă - un substituent. PDO acceptă substituenți poziționali (?), pentru care ordinea variabilelor trecute este importantă și substituenți denumiti (:nume), pentru care ordinea nu este importantă. Exemple:
$sql = ;
$sql = ;

Pentru a executa o astfel de interogare, trebuie mai întâi pregătită folosind funcția prepare(). De asemenea, returnează o declarație PDO, dar fără date încă. Pentru a le obține, trebuie să executați această solicitare, după ce ați trecut anterior variabile în ea. Îl poți transfera în două moduri:
Cel mai adesea, puteți executa pur și simplu metoda execute(), trecându-i o serie de variabile:
$stmt = $pdo -> pregătiți ( „SELECTează numele FROM utilizatorii WHERE email = ?”);
$stmt -> execute (array($email ));

$stmt = $pdo -> pregătiți ( „SELECTează numele FROM utilizatorii WHERE email = :email”);
$stmt -> execute (array("email" => $email ));
După cum puteți vedea, în cazul substituenților numiți, o matrice în care cheile trebuie să se potrivească cu numele substituenților trebuie să fie transmisă pentru a executa ().

Uneori, foarte rar, a doua metodă poate fi necesară, când variabilele sunt mai întâi legate la cerere pe rând, folosind bindValue() / bindParam(), și apoi doar executate. În acest caz, nu se trece nimic la execute(). Un exemplu poate fi găsit în manual.
Când utilizați această metodă, ar trebui să fie întotdeauna preferată bindValue()? deoarece comportamentul lui bindParam() nu este evident pentru începători și va duce la probleme.

Puteți utiliza apoi declarația PDO în aceleași moduri ca mai sus. De exemplu, prin foreach:
$stmt = $pdo -> pregătiți ( „SELECTează numele FROM utilizatorii WHERE email = ?”);
$stmt ->
foreach ($stmt ca $row )
{
echo $row [ „nume” ] . „\n” ;
}

IMPORTANT: Expresiile pregătite sunt motivul principal pentru a utiliza PDO deoarece acesta singura cale sigură executând interogări SQL care implică variabile.

De asemenea, prepare() / execute() poate fi folosit pentru a executa în mod repetat o interogare pregătită odată cu diferite seturi de date. În practică, acest lucru este necesar extrem de rar și nu aduce mult câștig de viteză. Dar în cazul în care trebuie să faceți mai multe interogări de același tip, puteți scrie astfel:

$date = matrice(
1 => 1000,
5 => 300,
9 => 200,
);

$stmt = $pdo -> pregătiți ( "UPDATE utilizatorii SET bonus = bonus + ? WHERE id = ?");
foreach ($date ca $id => $bonus)
{
$stmt -> execute ([ $bonus , $id ]);
}

Aici pregătim cererea o dată și apoi o executăm de mai multe ori.

Ne-am familiarizat deja cu metoda fetch(), care este folosită pentru a obține secvențial rânduri din baza de date. Această metodă este un analog al funcției mysq_fetch_array() și a altora similare, dar acționează diferit: în loc de multe funcții, aici este folosită una, dar comportamentul ei este specificat de parametrul transmis. Voi scrie despre acești parametri în detaliu mai târziu, dar ca o scurtă recomandare aș recomanda utilizarea fetch() în modul FETCH_LAZY:
$stmt = $pdo -> pregătiți ( „SELECTează numele FROM utilizatorii WHERE email = ?”);
$stmt -> execute([ $_GET [ "email" ]]);
while ($rând = $stmt -> preluare (PDO :: FETCH_LAZY ))
{
echo $rând [ 0 ] . „\n” ;
echo $row [ „nume” ] . „\n” ;
echo $rând -> nume . „\n” ;
}

În acest mod, nu se irosește memorie suplimentară și, în plus, coloanele pot fi accesate în oricare dintre trei moduri - prin index, nume sau proprietate.

Declarația PDO are și o funcție de ajutor pentru obținerea valorii unei singure coloane. Este foarte convenabil dacă solicităm un singur câmp - în acest caz, cantitatea de scris este redusă semnificativ:
$stmt = $pdo -> pregătiți ( „SELECTează numele din tabelul WHERE id=?”);
$stmt -> execute (array($id ));
$nume = $stmt -> fetchColumn();

Dar cea mai interesantă funcție, cu cea mai mare funcționalitate, este fetchAll(). Acesta este ceea ce face din PDO o bibliotecă de nivel înalt pentru lucrul cu o bază de date, și nu doar un driver de nivel scăzut.

FetchAll() returnează o matrice care constă din toate rândurile pe care le-a returnat interogarea. Din care se pot trage două concluzii:
1. Această funcție nu trebuie utilizată atunci când interogarea returnează o mulțime de date. În acest caz, este mai bine să utilizați o buclă tradițională cu fetch()
2. Deoarece în aplicațiile PHP moderne datele nu sunt niciodată scoase imediat după primire, ci sunt transferate într-un șablon în acest scop, fetchAll() devine pur și simplu de neînlocuit, permițându-vă să evitați scrierea manuală a buclelor și, prin urmare, reducând cantitatea de cod.

Obținerea unui tablou simplu.
Apelată fără parametri, această funcție returnează o matrice obișnuită indexată care conține rânduri din baza de date, în formatul specificat în FETCH_MODE în mod implicit. Constantele PDO::FETCH_NUM, PDO::FETCH_ASSOC, PDO::FETCH_OBJ pot schimba formatul din mers.

Obținerea unei coloane.
Uneori trebuie să obțineți o matrice simplă unidimensională solicitând un singur câmp dintr-o grămadă de șiruri. Pentru a face acest lucru, utilizați modul PDO::FETCH_COLUMN
$date = $pdo -> interogare ("SELECT name FROM users" ) -> fetchAll (PDO :: FETCH_COLUMN );
matrice (
0 => „Ioan” ,
1 => „Mike” ,
2 => „Maria” ,
3 => "Kathy" ,
)

Se preiau perechi cheie-valoare.
De asemenea, un format popular atunci când este de dorit să obțineți aceeași coloană, dar indexată nu după numere, ci după unul dintre câmpuri. Constanta PDO::FETCH_KEY_PAIR este responsabilă pentru acest lucru.
$date = $pdo -> interogare ("SELECT id, name FROM users" ) -> fetchAll (PDO :: FETCH_KEY_PAIR );
matrice (
104 => "Ioan" ,
110 => "Mike" ,
120 => "Maria" ,
121 => "Kathy" ,
)

Obțineți toate rândurile indexate după un câmp.
De asemenea, este adesea necesar să obțineți toate rândurile din baza de date, dar și indexate nu după numere, ci printr-un câmp unic. Constanta PDO::FETCH_UNIQUE face acest lucru.
$date = $pdo -> interogare ("SELECT * FROM users") -> fetchAll (PDO :: FETCH_UNIQUE );
matrice (
104 => matrice (
"name" => "Ioan" ,
"mașină" => "Toyota" ,
),
110 => matrice (
"name" => "Mike" ,
"mașină" => "Ford" ,
),
120 => matrice (
"name" => "Maria" ,
"mașină" => "Mazda" ,
),
121 => matrice (
"name" => "Kathy" ,
"mașină" => "Mazda" ,
),
)

Trebuie reținut că trebuie să selectați mai întâi un câmp unic în coloană.

Există mai mult de o duzină și jumătate de moduri diferite de achiziție de date în PDO. Plus că le poți combina! Dar acesta este un subiect pentru un articol separat.

Când lucrați cu expresii pregătite, ar trebui să înțelegeți că un substituent poate înlocui doar un șir sau un număr. Nici un cuvânt cheie, nici un identificator, nici o parte dintr-un șir sau un set de șiruri nu pot fi înlocuite printr-un substituent. Prin urmare, pentru LIKE trebuie mai întâi să pregătiți întregul șir de căutare și apoi să îl înlocuiți în interogare:

$nume = "% $nume %" ;
$stm = $pdo -> pregătiți ( "SELECT * FROM tabelul WHERE nume LIKE?");
$stm -> execute (matrice($nume));
$date = $stm -> fetchAll();

Ei bine, ai înțeles ideea. Totul este rău și aici. PDO nu oferă deloc instrumente pentru lucrul cu identificatorii, iar aceștia trebuie formatați în mod demodat, manual (sau, totuși, priviți spre SafeMysql, în care acest lucru, la fel ca multe alte probleme, este rezolvat simplu și elegant).
Trebuie amintit că regulile de formatare a identificatorilor diferă pentru diferite baze de date.

În mysql, pentru a formata manual un identificator, trebuie să faceți două lucruri:
- închideți-l în backticks ("`").
- căutați aceste caractere în interiorul identificatorului prin dublare.

$câmp = "`" . str_replace ("`" , "``" , $_GET [ "câmp" ]). "`" ;
$sql = $câmp " ;

Cu toate acestea, există o avertizare aici. Formatarea singură poate să nu fie suficientă. Codul de mai sus ne protejează de injectarea clasică, dar în unele cazuri inamicul poate scrie ceva nedorit dacă înlocuim fără grija numele câmpurilor și tabelelor direct în interogare. De exemplu, există un câmp de administrare în tabelul utilizatori. Dacă numele câmpurilor primite nu sunt filtrate, atunci orice prost va scrie orice lucru urât în ​​acest câmp atunci când generează automat o solicitare de la un POST.

Prin urmare, este recomandabil să verificați valabilitatea numelor tabelelor și câmpurilor provenite de la utilizator, ca în exemplul de mai jos

Orice cod de încorporare care poate fi văzut în numeroase tutoriale aduce melancolie și dorința de a ucide apstenul. Construcții multikilometrice cu repetarea acelorași nume - în indexurile $_POST, în nume de variabile, în nume de câmpuri într-o cerere, în nume de substituenți într-o cerere, în nume de substituenți și nume de variabile la legare.
Privind acest cod, îmi doresc să ucid pe cineva, sau cel puțin să-l fac puțin mai scurt.

Acest lucru se poate face prin adoptarea unei convenții conform căreia numele câmpurilor din formular se potrivesc cu numele câmpurilor din tabel. Apoi, aceste nume pot fi listate o singură dată (pentru a proteja împotriva înlocuirii, care a fost menționat mai sus), și o mică funcție de ajutor poate fi utilizată pentru a asambla interogarea, care, datorită particularităților mysql, este potrivită atât pentru INSERT, cât și pentru ACTUALIZARE interogări:

funcția pdoSet ($permis și $valori, $sursă = matrice()) (
$set = "" ;
$valori = matrice();
if (! $sursa ) $sursa = & $_POST ;
foreach ($permis ca $câmp) (
if (isset($sursa [ $câmp])) (
$set .= "`" . str_replace ("`" , "``" , $câmp ). „`”. "=: $câmp , " ;
$valori [ $câmp ] = $sursă [ $câmp ];
}
}
return substr ($set, 0, - 2);
}

În consecință, codul de încorporare va fi

$allowed = array("nume", "nume" , "e-mail"); // câmpuri permise
$sql = "INSERT INTO users SET " . pdoSet ($permis, $valori);
$stm = $dbh -> pregăti ($sql );
$stm -> execute ($valori);

Și pentru actualizare - aceasta:

$allowed = array("nume", "nume" , "e-mail" , "parolă"); // câmpuri permise
$_POST ["parolă" ] = MD5 ($_POST [ "login" ]. $_POST [ "parolă" ]);
$sql = "UPDATE users SET " . pdoSet ($permis, $valori). „WHERE id = :id” ;
$stm = $dbh -> pregăti ($sql );
$values ​​​​["id" ] = $_POST ["id" ];
$stm -> execute ($valori);

Nu foarte impresionant, dar foarte eficient. Permiteți-mi să vă reamintesc, apropo, că dacă utilizați Class pentru a lucra sigur și convenabil cu MySQL, atunci totul se face în două rânduri.

DOP și cuvinte cheie
Este imposibil să veniți cu altceva decât filtrarea aici. Prin urmare, este o prostie să rulezi toți operatorii nespecificați direct în cerere prin lista albă:

$dirs = array("ASC" , "DESC" );
$key = array_search($_GET["dir"], $dirs));
$dir = $comenzi [ $cheie ];
$sql = „SELECT * FROM `table` ORDER BY$câmp $dir " ;

Termen DOP este o abreviere a conceptului Obiecte de date PHP. După cum sugerează și numele, această tehnologie vă permite să lucrați cu conținutul bazei de date prin obiecte.

De ce nu myqli sau mysql?

Cel mai adesea, în ceea ce privește noile tehnologii, se pune întrebarea cu privire la avantajele acestora față de instrumentele bune vechi și dovedite, precum și transferul proiectelor actuale și vechi către acestea.

Orientare obiect PDO

PHP Se dezvoltă foarte activ și se străduiește să devină unul dintre cele mai bune instrumente pentru dezvoltarea rapidă a aplicațiilor web, atât la nivel de masă, cât și la nivel corporativ.

Vorbind despre PHP, ne referim la modern orientat pe obiecte PHP, permițându-vă să scrieți cod universal care este convenabil pentru testare și reutilizare.

Utilizare DOP vă permite să mutați baza de date la un nivel orientat pe obiect și să îmbunătățiți portabilitatea codului. De fapt, utilizarea DOP nu atât de dificil pe cât s-ar putea crede.

Abstracția

Să ne imaginăm că dezvoltăm o aplicație de mult timp folosind MySQL. Și apoi, la un moment bun, devine necesară înlocuirea MySQL pe PostgreSQL.

Cel puțin, va trebui să înlocuim toate apelurile mysqli_connect() (mysql_connect()) pe pg_connect()și, prin analogie, alte funcții utilizate pentru interogarea și procesarea datelor.

Când se utilizează DOP, ne vom limita la modificarea câțiva parametri din fișierele de configurare.

Legarea parametrilor

Utilizarea parametrilor legați oferă o mai mare flexibilitate în proiectarea interogărilor și îmbunătățește protecția împotriva SQL injecții.

Primirea datelor ca obiecte

Cei care deja folosesc ORM(mapping obiect-relațional - mapare obiect-relațională a datelor), de exemplu, Doctrină, cunoașteți comoditatea reprezentării datelor din tabelele bazei de date sub formă de obiecte. DOP vă permite să primiți date sub formă de obiecte și fără a utiliza ORM.

Extensia mysql nu mai este acceptată

Suport extensie mysql eliminat definitiv din nou PHP 7. Dacă intenționați să migrați proiectul la o versiune nouă PHP, ar trebui să utilizați cel puțin mysqli în el acum. Desigur, este mai bine să începeți să utilizați DOP dacă nu ai făcut-o deja.

Mi se pare că aceste motive sunt suficiente pentru a înclina balanța în favoarea utilizării DOP. În plus, nu trebuie să instalați nimic suplimentar.

Verificarea prezenței DOP în sistem

Versiuni PHP 5.5și mai mare, cel mai adesea, conțin deja o extensie pentru a lucra cu DOP. Pentru a verifica, rulați o comandă simplă în consolă:

php -i | grep "pdo"

Acum să-l deschidem în orice browser și să găsim datele necesare căutând după linie DOP.

Cunoașterea DOP

Procesul de lucru cu DOP nu prea diferit de cel tradițional. În general, procesul de utilizare DOP arata asa:

  1. Conectați-vă la baza de date;
  2. Dacă este necesar, pregătiți o solicitare și parametrii de legătură;
  3. Executarea cererii.

Conectarea la baza de date

Pentru a vă conecta la baza de date trebuie să creați un nou obiect DOPși transmiteți-i numele sursei de date, cunoscut și ca DSN.

In general, DSN constă din numele driverului separat prin două puncte de un șir de conexiune specific fiecărui driver DOP.

Pentru MySQL, conexiunea se face astfel:

$conexiune = PDO nou ("mysql:host=localhost;dbname=mydb;charset=utf8", "root", "root");

$conexiune = PDO nou ( „mysql:host=localhost;dbname=mydb;charset=utf8”, „rădăcină” , „rădăcină” );

În acest caz, DSN conține numele șoferului mysql, indicație gazdă (format posibil gazdă=HOST_NAME:PORT), numele bazei de date, codificare, nume de utilizator MySQLși parola lui.

Cereri

Spre deosebire de mysqli_query(), V DOP există două tipuri de cereri:

  • Returnarea rezultatului ( selectați, afișați);
  • Nu returnează un rezultat ( introduce, detaliuși altele).

În primul rând, să luăm în considerare a doua opțiune.

Executarea interogărilor

Să ne uităm la un exemplu de executare a unei cereri folosind exemplul introduce.

$connection->exec("INSERT INTO users VALUES (1, "somevalue"");

$conexiune -> exec () ;

Desigur, această interogare returnează numărul de rânduri afectate și îl puteți vedea după cum urmează.

$affectedRows = $connection->exec("INSERT INTO user VALUES (1, "somevalue""); echo $affectedRows;

$affectedRows = $conexiune -> exec ( „INSERT INTO users VALUES (1, „somevalue””) ;

echo $afectedRows ;

Obținerea rezultatelor interogării

În caz de utilizare mysqli_query(), codul ar putea fi după cum urmează.

$rezultat = mysql_query("SELECT * FROM utilizatori"); while($row = mysql_fetch_assoc($result)) ( echo $row["id"] . " " . $row["nume"]; )

$rezultat = mysql_query ("SELECT * FROM utilizatori");

while ($rând = mysql_fetch_assoc ($rezultat) ) (

Pentru DOP, codul va fi mai simplu și mai concis.

foreach($connection->query("SELECT * FROM users") ca $row) ( echo $row["id"] . " " . $row["nume"]; )

foreach ($connection -> interogare ("SELECT * FROM users") ca $row ) (

echo $row [ "id" ] . " " . $row[„nume”];

Moduri de achiziție a datelor

Ca în mysqli, DOP vă permite să primiți date în diferite moduri. Pentru a determina modul, clasa DOP conţine constantele corespunzătoare.

  • PDO::FETCH_ASSOC— returnează o matrice indexată după numele coloanei din tabelul bazei de date;
  • PDO::FETCH_NUM— returnează o matrice indexată după numărul coloanei;
  • PDO::FETCH_OBJ- returnează un obiect anonim cu nume de proprietate corespunzătoare numelor de coloană. De exemplu, $row->id va conține valoarea din coloana id.
  • PDO::FETCH_CLASS— returnează o nouă instanță a clasei, cu valorile proprietăților corespunzătoare datelor din rândul tabelului. Dacă parametrul este specificat PDO::FETCH_CLASSTYPE(De exemplu PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE

), numele clasei va fi determinat din valoarea primei coloane. Nota

: Aceasta nu este o listă completă a tuturor constantelor posibile și combinațiile lor sunt disponibile în documentație.

Un exemplu de obținere a unui tablou asociativ:

$statement = $conexiune->interogare("SELECT * FROM utilizatori"); while($row = $statement->fetch(PDO::FETCH_ASSOC)) ( echo $row["id"] . " " . $row["nume"]; )

$statement = $conexiune ->

echo $row [ "id" ] . " " . $row[„nume”];

), numele clasei va fi determinat din valoarea primei coloane. while ($row = $statement -> fetch (PDO::FETCH_ASSOC) ) ( : Este recomandat să specificați întotdeauna modul de eșantionare deoarece modul PDO::FETCH_BOTH

va necesita de două ori mai multă memorie - de fapt, vor fi create două tablouri, asociative și regulate. PDO::FETCH_CLASS Luați în considerare utilizarea modului de eșantionare . Să creăm o clasă:

Utilizator

clasa Utilizator ( $id protejat; $nume protejat; funcția publică getId() ( return $this->id; ) public function setId($id) ( $this->id = $id; ) funcția publică getName() ( return $this->name ) public function setName($nume) ( $this->name = $nume; ) )

clasa Utilizator

protejat $id ;

protejat $nume ;

returnează $this -> id ;

setId funcție publică ($id)

$acest -> id = $id ;

funcția publică getName()

returnează $acest -> nume ;

funcția public setName ($nume)

$acest -> nume = $nume ;

Acum să selectăm datele și să le afișăm folosind metodele clasei:

$statement = $conexiune->interogare("SELECT * FROM utilizatori"); while($row = $statement->fetch(PDO::FETCH_CLASS, „Utilizator”)) ( echo $row->getId() . " " . $row->getName(); )

$statement = $conexiune -> interogare ("SELECT * FROM utilizatori");

while ($row = $statement -> fetch (PDO::FETCH_CLASS, „Utilizator”)) (

echo $row -> getId() . " " . $row -> getName () ;

Interogări pregătite și legarea parametrilor

Pentru a înțelege esența și toate beneficiile legării parametrilor, trebuie să aruncați o privire mai atentă asupra mecanismelor DOP. Când suni $statement -> interogare() in codul de mai sus, DOP va pregăti o cerere, o va executa și va returna rezultatul.

Când suni $conexiune -> pregătiți() se creează o cerere pregătită. Interogările pregătite reprezintă capacitatea unui sistem de gestionare a bazei de date de a primi un șablon de interogare, de a-l compila și de a-l executa după preluarea valorilor variabilelor utilizate în șablon. Motoarele de șabloane funcționează într-un mod similar. inteligentŞi Crenguţă.

Când suni $statement -> execute() valorile pentru înlocuire sunt transferate în șablonul de interogare și DBMS execută interogarea. Această acțiune este similară cu apelarea funcției motor de șablon face().

Un exemplu de utilizare a interogărilor pregătite în PHP DOP:

În codul de mai sus, este pregătită o cerere de selectare a unei înregistrări cu un câmp id egală cu valoarea care va fi înlocuită : id. În această etapă, SGBD va analiza și compila cererea, eventual folosind caching (în funcție de setări).

Acum trebuie să treceți parametrul lipsă și să executați cererea:

$id = 5; $statement->execute([ ":id" => $id ]);

Beneficiile utilizării parametrilor legați

Poate că, după examinarea modului în care funcționează interogările pregătite și a parametrilor asociați, beneficiile utilizării lor devin evidente.

DOP oferă o modalitate convenabilă de a scăpa de datele utilizatorului, de exemplu, codul ca acesta nu mai este necesar:

În schimb, acum este recomandabil să faceți acest lucru:

Puteți chiar să scurtați și mai mult codul utilizând parametri numerotați în loc de cei numiți:

În același timp, utilizarea interogărilor pregătite îmbunătățește performanța atunci când se utilizează de mai multe ori același șablon de interogare. Un exemplu de selectare a cinci utilizatori aleatoriu dintr-o bază de date:

$numberOfUsers = $connection->query("SELECT COUNT(*) FROM users")->fetchColumn(); $utilizatori = ; $statement = $conexiune->prepare("SELECT * FROM users WHERE id = ? LIMIT 1"); pentru ($i = 1; $i<= 5; $i++) { $id = rand(1, $numberOfUsers); $users = $statement->execute([$id])->fetch(PDO::FETCH_OBJ); )

$numberOfUsers = $conexiune -> interogare ("SELECT COUNT(*) FROM users" ) -> fetchColumn () ;

$utilizatori = ;

pentru ($i = 1; $i<= 5 ; $i ++ ) {

$id = rand (1, $numarDeUtilizatori) ;

$users = $statement -> execute ([ $id ] ) -> fetch (PDO::FETCH_OBJ ) ;

La apelarea unei metode pregăti(), SGBD-ul va analiza și compila cererea, folosind caching-ul dacă este necesar. Mai târziu în ciclu pentru, numai datele sunt eșantionate cu parametrul specificat. Această abordare vă permite să recuperați datele mai rapid, reducând timpul de rulare a aplicației.

La obținerea numărului total de utilizatori din baza de date, a fost utilizată metoda fetchColumn(). Această metodă preia valoarea unei singure coloane și este utilă atunci când se regăsesc valori scalare, cum ar fi numărul, suma, valorile maxime sau minime.

Valori legate și operatorul IN

Adesea, când începe să lucrezi cu DOP, apar dificultăți cu operatorul ÎN. De exemplu, imaginați-vă că utilizatorul introduce mai multe nume separate prin virgule. Intrarea utilizatorului este stocată într-o variabilă $nume.

Configurarea și utilizarea extensiei PDO - PHP Data Objects pentru lucrul cu baze de date

Crearea unei baze de date și a unui tabel de testare

Mai întâi, să creăm baza de date pentru acest tutorial:

CREATE DATABASE solar_system; Acordați TOATE PRIVILEGIILE PE solar_system.* CĂTRE „testuser”@“localhost” IDENTIFICAT DE „testpassword”;

Un utilizator cu utilizatorul de conectare și parola testpassword i s-au acordat drepturi de acces complete la baza de date solar_system.

Acum să creăm un tabel și să-l umplem cu date, a căror acuratețe astronomică nu este implicită:

USE solar_system; CREATE TABLE planete (id TINYINT(1) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY(id), nume VARCHAR(10) NOT NULL, culoare VARCHAR(10) NOT NULL); INSERT INTO planete(nume, culoare) VALUES("pământ", "albastru"), ("marte", "roșu"), ("jupiter", "ciudat");

Descrierea conexiunii

Acum că baza de date a fost creată, să definim DSN () - informații pentru conectarea la baza de date, prezentate ca șir. Sintaxa descrierii diferă în funcție de SGBD utilizat. În exemplu lucrăm cu MySQL/MariaDB, așa că indicăm:

  • numele gazdă unde se află SGBD;
  • port (opțional dacă este utilizat portul standard 3306);
  • numele bazei de date;
  • codificare (opțional).

Linia DSN în acest caz arată astfel:

$dsn = "mysql:host=localhost;port=3306;dbname=sistem_solar;charset=utf8";

Prefixul bazei de date este specificat mai întâi. În exemplu - mysql. Prefixul este separat de restul liniei prin două puncte, iar fiecare parametru ulterior este separat printr-un punct și virgulă.

Crearea unui obiect PDO

Acum că șirul DSN este gata, să creăm un obiect PDO. Constructorul de intrare acceptă următorii parametri:

  1. șir DSN.
  2. Numele utilizatorului care are acces la baza de date.
  3. Parola acestui utilizator.
  4. O matrice cu parametri suplimentari (opțional).
$opțiuni = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ]; $pdo = PDO nou($dsn, „testuser”, „testpassword”, $opțiuni);

Parametrii suplimentari pot fi definiți și după ce obiectul este creat folosind metoda SetAttribute:

$pdo->SetAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Definirea metodei implicite de eșantionare

PDO::DEFAULT_FETCH_MODE este un parametru important care determină metoda implicită de preluare. Metoda specificată este utilizată la obținerea rezultatului unei cereri.

PDO::FETCH_BOTH

Modul implicit. Rezultatul selecției este indexat atât de numere (începând de la 0) cât și de numele coloanelor:

$stmt = $pdo->query("SELECT * FROM planete"); $rezultate = $stmt->fetch(PDO::FETCH_BOTH);

După ce executăm o interogare cu acest mod împotriva tabelului de test al planetelor, obținem următorul rezultat:

Matrice ( => 1 => 1 => pământ => pământ => albastru => albastru)

PDO::FETCH_ASSOC

Rezultatul este stocat într-o matrice asociativă în care cheia este numele coloanei și valoarea este valoarea rândului corespunzătoare:

$stmt = $pdo->query("SELECT * FROM planete"); $rezultate = $stmt->fetch(PDO::FETCH_ASSOC);

Ca rezultat obținem:

Matrice ( => 1 => pământ => albastru)

PDO::FETCH_NUM

Când utilizați acest mod, rezultatul este prezentat ca o matrice indexată după numerele coloanei (începând de la 0):

Matrice ( => 1 => pământ => albastru)

PDO::FETCH_COLUMN

Această opțiune este utilă dacă trebuie să obțineți o listă de valori pentru un câmp sub forma unei matrice unidimensionale, a cărei numerotare începe de la 0. De exemplu:

$stmt = $pdo->query("SELECT numele de la planete");

Ca rezultat obținem:

Matrice ( => pământ => Marte => jupiter)

PDO::FETCH_KEY_PAIR

Folosim această opțiune dacă trebuie să obținem o listă de valori a două câmpuri sub forma unui tablou asociativ. Cheile matricei sunt datele din prima coloană a selecției, valorile matricei sunt datele din a doua coloană. De exemplu:

$stmt = $pdo->query("SELECT numele, culoarea FROM planete"); $rezultat = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);

Ca rezultat obținem:

Matrice ( => albastru => roșu => ciudat)

PDO::FETCH_OBJECT

Când utilizați PDO::FETCH_OBJECT, este creat un obiect anonim pentru fiecare rând preluat. Proprietățile sale publice sunt numele coloanelor eșantion, iar rezultatele interogării sunt folosite ca valori:

$stmt = $pdo->query("SELECT numele, culoarea FROM planete"); $rezultate = $stmt->fetch(PDO::FETCH_OBJ);

Ca rezultat obținem:

Obiect StdClass ( => pământ => albastru)

PDO::FETCH_CLASS

În acest caz, ca și în cel precedent, valorile coloanei devin proprietăți ale obiectului. Cu toate acestea, trebuie să specificați o clasă existentă care va fi folosită pentru a crea obiectul. Să ne uităm la asta cu un exemplu. Mai întâi, să creăm o clasă:

Class Planet ( privat $nume; privat $culoare; funcția public setName($planet_name) ( $this->name = $planet_name; ) public function setColor($planet_culore) ( $this->color = $planet_culo; ) public function getName () ( returnează $this->nume; ) funcția publică getColor() ( returnează $this->culoare; ) )

Vă rugăm să rețineți că clasa Planet are proprietăți private și nu are un constructor. Acum să executăm cererea.

Dacă utilizați metoda fetch cu PDO::FETCH_CLASS , trebuie să utilizați metoda setFetchMode înainte de a trimite o solicitare de preluare a datelor:

$stmt = $pdo->query("SELECT numele, culoarea FROM planete"); $stmt->setFetchMode(PDO::FETCH_CLASS, "Planeta");

Primul parametru pe care îl transmitem metodei setFetchMode este constanta PDO::FETCH_CLASS. Al doilea parametru este numele clasei care va fi folosită la crearea obiectului. Acum hai sa facem:

$planeta = $stmt->fetch(); var_dump($planeta);

Ca rezultat, obținem un obiect Planet:

Obiect Planet ( => pământ => albastru)

Valorile returnate de interogare sunt atribuite proprietăților corespunzătoare ale obiectului, chiar și celor private.

Definirea proprietăților după execuția constructorului

Clasa Planet nu are un constructor explicit, deci nu vor fi probleme de atribuire a proprietăților. Dacă o clasă are un constructor în care proprietatea a fost atribuită sau schimbată, acestea vor fi suprascrise.

Când utilizați constanta FETCH_PROPS_LATE, valorile proprietăților vor fi alocate după ce constructorul este executat:

Class Planet ( privat $nume; privat $culoare; funcția publică __construct($nume = lună, $culoare = gri) ( $this->nume = $nume; $this->culoare = $culoare; ) public function setName($ planet_name) ( $this->name = $planet_name; ) public function setColor($planet_color) ( $this->color = $planet_culo; ) public function getName() ( return $this->name; ) public function getColor() ( returnează $this->color; ) )

Am modificat clasa Planet adăugând un constructor care ia ca intrare două argumente: nume și culoare. Valorile implicite pentru aceste câmpuri sunt luna și, respectiv, gri.

Dacă nu utilizați FETCH_PROPS_LATE, proprietățile vor fi suprascrise cu valorile implicite atunci când obiectul este creat. Să verificăm. Mai întâi să rulăm interogarea:

$stmt = $pdo->query("SELECT nume, culoare FROM solar_system WHERE nume = "pământ""); $stmt->setFetchMode(PDO::FETCH_CLASS, "Planeta"); $planeta = $stmt->fetch(); var_dump($planeta);

Ca rezultat obținem:

Object(Planeta)#2 (2) ( ["nume":"Planeta":privat]=> string(4) "luna" ["culoare":"Planeta":privat]=> string(4) "gri" )

După cum era de așteptat, valorile preluate din baza de date sunt suprascrise. Acum să ne uităm la rezolvarea problemei folosind FETCH_PROPS_LATE (o solicitare similară):

$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, „Planeta”); $planeta = $stmt->fetch(); var_dump($planeta);

Drept urmare, obținem ceea ce avem nevoie:

Object(Planeta)#4 (2) ( ["nume":"Planeta":privat]=> string(5) "pământ" ["culoare":"Planeta":privat]=> string(4) "albastru" )

Dacă un constructor de clasă nu are valori implicite, dar acestea sunt necesare, parametrii constructorului sunt setați la apelarea metodei setFetchMode cu al treilea argument sub forma unui tablou. De exemplu:

Clasa Planeta ( privat $nume; privat $culoare; function public __construct($nume, $culoare) ( $this->nume = $nume; $this->culoare = $culoare; ) [...] )

Argumentele constructorului sunt necesare, deci să facem:

$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, "Planeta", ["luna", "gri"]);

Parametrii primiți acționează și ca valori implicite care sunt necesare pentru inițializare. În viitor, acestea vor fi suprascrise cu valori din baza de date.

Preluarea mai multor obiecte

Mai multe rezultate sunt preluate ca obiecte folosind metoda fetch în interiorul unei bucle while:

While ($planet = $stmt->fetch()) ( // procesează rezultatele )

Sau prin eșantionarea tuturor rezultatelor simultan. În al doilea caz, se folosește metoda fetchAll, iar modul este specificat în momentul apelului:

$stmt->fetchAll(PDO::FETCH_CLASS|PDO_FETCH_PROPS_LATE, „Planeta”, [„lună”, „gri”]);

PDO::FETCH_INTO

Când această opțiune de selecție este selectată, PDO nu creează un obiect nou, ci mai degrabă actualizează proprietățile celui existent. Cu toate acestea, acest lucru este posibil numai pentru proprietăți publice sau când se utilizează metoda magic __set pe obiect.

Cereri pregătite și directe

Există două moduri de a executa interogări în PDO:

  • drept, care constă dintr-o treaptă;
  • pregătit, care constă din două etape.

Cereri directe

Există două metode pentru a efectua interogări directe:

  • interogarea este utilizată pentru instrucțiunile care nu fac modificări, cum ar fi SELECT. Returnează un obiect PDOStatemnt din care rezultatele interogării sunt preluate folosind metodele fetch sau fetchAll;
  • exec este folosit pentru instrucțiuni precum INSERT, DELETE sau UPDATE. Returnează numărul de rânduri procesate de cerere.

Operatorii direcți sunt utilizați numai dacă nu există variabile în interogare și sunteți sigur că interogarea este sigură și scăpată corect.

Interogări pregătite

PDO acceptă instrucțiuni pregătite, care sunt utile pentru protejarea unei aplicații de: metoda prepare realizează evadarea necesară.

Să ne uităm la un exemplu. Doriți să inserați proprietățile unui obiect Planet în tabelul Planete. Mai întâi, să pregătim cererea:

$stmt = $pdo->prepare("INSERT INTO planete(nume, culoare) VALORI(?, ?)");

Folosim metoda prepare, care ia ca argument o interogare SQL cu pseudo-variabile (substituenți). Pseudovariabilele pot fi de două tipuri: nenumite și numite.

Pseudovariabile fără nume

Pseudovariabilele nenumite (substituenți poziționali) sunt marcate cu ? . Interogarea rezultată este compactă, dar necesită ca valorile să fie înlocuite în aceeași ordine. Ele sunt transmise ca o matrice prin metoda execute:

$stmt->execute([$planeta->nume, $planeta->culoare]);

Pseudovariabile numite

Când folosiți substituenți numiți, ordinea în care valorile sunt transmise pentru înlocuire nu este importantă, dar codul în acest caz devine mai puțin compact. Datele sunt transmise metodei execute sub forma unui tablou asociativ, în care fiecare cheie corespunde numelui unei pseudo-variabile, iar valoarea matricei corespunde valorii care trebuie înlocuită în cerere. Să refacem exemplul anterior:

$stmt = $pdo->prepare("INSERT INTO planete(nume, culoare) VALORI(:nume, :culoare)"); $stmt->execute(["nume" => $planeta->nume, "culoare" => $planeta->culoare]);

Metodele de pregătire și execuție sunt utilizate atât la executarea cererilor de modificare, cât și la preluare.

Și informații despre numărul de rânduri procesate, dacă este necesar, vor fi furnizate prin metoda rowCount.

Controlul comportamentului erorii PDO

Parametrul de selectare a modului de eroare PDO::ATTR_ERRMODE este utilizat pentru a determina modul în care se comportă PDO în cazul unor erori. Există trei opțiuni disponibile: PDO::ERRMODE_SILENT , PDO::ERRMODE_EXCEPTION și PDO::ERRMODE_WARNING .

PDO::ERRMODE_SILENT

Opțiune implicită. PDO va înregistra pur și simplu informații despre eroare, pe care metodele errorCode și errorInfo vă vor ajuta să le obțineți.

PDO::ERRMODE_EXCEPTION

Aceasta este opțiunea preferată în care PDO aruncă o excepție (PDOException) în plus față de informațiile despre eroare. O excepție întrerupe execuția scriptului, ceea ce este util atunci când se utilizează tranzacții PDO. Un exemplu este dat în descrierea tranzacțiilor.

PDO::ERRMODE_WARNING

În acest caz, PDO înregistrează și informații despre eroare. Fluxul de script nu este întrerupt, dar sunt emise avertismente.

metodele bindValue și bindParam

De asemenea, puteți utiliza metodele bindValue și bindParam pentru a înlocui valorile într-o interogare. Prima asociază valoarea variabilei cu pseudovariabila care este utilizată pentru pregătirea cererii:

$stmt = $pdo->prepare("INSERT INTO planete(nume, culoare) VALORI(:nume, :culoare)"); $stmt->bindValue("nume", $planeta->nume, PDO::PARAM_STR);

A legat valoarea variabilei $planet->name de pseudovariabila:nume . Rețineți că atunci când utilizați metodele bindValue și bindParam, tipul variabilei este specificat ca al treilea argument folosind constantele PDO corespunzătoare. În exemplu - PDO::PARAM_STR .

Metoda bindParam leagă o variabilă la o pseudo variabilă. În acest caz, variabila este asociată cu o referință pseudo-variabilă, iar valoarea va fi inserată în interogare numai după apelarea metodei execute. Să ne uităm la un exemplu:

$stmt->bindParam("nume", $planeta->nume, PDO::PARAM_STR);

Tranzacții în DOP

Să ne imaginăm un exemplu neobișnuit. Utilizatorul trebuie să selecteze o listă de planete, iar de fiecare dată când cererea este executată, datele curente sunt șterse din baza de date, iar apoi sunt inserate altele noi. Dacă apare o eroare după ștergere, următorul utilizator va primi o listă goală. Pentru a evita acest lucru, folosim tranzacții:

$pdo->beginTransaction(); încercați ( $stmt1 = $pdo->exec("ȘTERGERE DE PE planete"); $stmt2 = $pdo->prepare("INSERT INTO planete(nume, culoare) VALORI (?, ?)"); foreach ($planete ca $planeta) ( $stmt2->execute([$planeta->getName(), $planeta->getColor()]); ) $pdo->commit() ) catch (PDOException $e) ( $pdo-> rollBack ();

Metoda beginTransaction dezactivează execuția automată a cererilor, iar în interiorul constructului try-catch, cererile sunt executate în ordinea dorită. Dacă nu se aruncă nicio excepție PDO, cererile vor fi finalizate folosind metoda commit. În caz contrar, acestea vor fi anulate folosind metoda rollback și va fi restabilită execuția automată a interogărilor.

Acest lucru a creat consistență în execuția interogărilor. Evident, pentru ca acest lucru să se întâmple, PDO::ATTR_ERRMODE trebuie setat la PDO::ERRMODE_EXCEPTION .

Concluzie

Acum că lucrul cu PDO a fost descris, să notăm principalele sale avantaje:

  • cu PDO este ușor să transferați aplicația în alte SGBD;
  • Toate SGBD-urile populare sunt acceptate;
  • sistem de management al erorilor încorporat;
  • diverse opțiuni pentru prezentarea rezultatelor eșantionului;
  • sunt acceptate interogări pregătite, care scurtează codul și îl fac rezistent la injecțiile SQL;
  • Sunt acceptate tranzacțiile, ceea ce ajută la menținerea integrității datelor și a coerenței interogărilor atunci când utilizatorii lucrează în paralel.
  • Traducere

Mulți dezvoltatori PHP sunt obișnuiți să folosească extensiile mysql și mysqli pentru a lucra cu baze de date. Dar, începând cu versiunea 5.1 în PHP, există o modalitate mai convenabilă - PHP Data Objects. Această clasă, numită pe scurt PDO, oferă metode de lucru cu obiecte și declarații pregătite care vă vor îmbunătăți semnificativ productivitatea!

Introducere în DOP

„PDO – PHP Data Objects este un strat care oferă o modalitate universală de a lucra cu mai multe baze de date.”

Lasă preocuparea pentru caracteristicile de sintaxă ale diferitelor SGBD-uri în seama dezvoltatorului, dar face procesul de comutare între platforme mult mai puțin dureros. Adesea, aceasta necesită doar schimbarea șirului de conexiune la baza de date.


Acest articol este scris pentru persoanele care folosesc mysql și mysqli pentru a-i ajuta să migreze la PDO mai puternic și mai flexibil.

Suport DBMS

Această extensie poate suporta orice sistem de gestionare a bazelor de date pentru care există un driver PDO. La momentul scrierii, sunt disponibile următoarele drivere:
  • PDO_CUBRID (CUBRID)
  • PDO_DBLIB (FreeTDS / Microsoft SQL Server / Sybase)
  • PDO_FIREBIRD (Firebird/Interbase 6)
  • PDO_IBM (IBM DB2)
  • PDO_INFORMIX (Server dinamic IBM Informix)
  • PDO_MYSQL (MySQL 3.x/4.x/5.x)
  • PDO_OCI (Interfață de apel Oracle)
  • PDO_ODBC (ODBC v3 (IBM DB2, unixODBC și win32 ODBC))
  • PDO_PGSQL (PostgreSQL)
  • PDO_SQLITE (SQLite 3 și SQLite 2)
  • PDO_SQLSRV (Microsoft SQL Server)
  • PDO_4D (4D)
Cu toate acestea, nu toate sunt pe serverul dvs. Puteți vedea lista de drivere disponibile astfel:
print_r(PDO::getAvailableDrivers());

Conexiune

Metodele de conectare la diferite SGBD-uri pot diferi ușor. Mai jos sunt exemple de conectare la cele mai populare. Veți observa că primele trei au sintaxă identică, spre deosebire de SQLite.
încercați ( # MS SQL Server și Sybase prin PDO_DBLIB $DBH = PDO nou ("mssql:host=$host;dbname=$dbname", $user, $pass); $DBH = PDO nou ("sybase:host=$host ;dbname=$dbname", $user, $pass); # MySQL prin PDO_MYSQL $DBH = PDO nou ("mysql:host=$host;dbname=$dbname", $user, $pass); # SQLite $DBH = new PDO("sqlite:my/database/path/database.db" catch(PDOException $e) ( echo $e->getMessage(); )
Vă rugăm să acordați atenție blocului try/catch - merită întotdeauna să includeți toate operațiunile dvs. PDO în el și să utilizați mecanismul de excepție (mai multe despre asta mai târziu).

$DBH înseamnă „mânerul bazei de date” și va fi folosit pe tot parcursul articolului.

Puteți închide orice conexiune prin redefinirea variabilei sale la null.
# închide conexiunea $DBH = null;
Mai multe informații despre opțiunile distinctive ale diferitelor SGBD-uri și metodele de conectare la acestea pot fi găsite pe php.net.

Excepții și DOP

PDO poate arunca excepții la erori, așa că totul ar trebui să fie într-un bloc try/catch. Imediat după crearea unei conexiuni, PDO poate fi pus în oricare dintre cele trei moduri de eroare:
$DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Dar este de remarcat faptul că o eroare atunci când încercați să vă conectați va arunca întotdeauna o excepție.

PDO::ERRMODE_SILENT

Acesta este modul implicit. Probabil că veți folosi aproximativ același lucru pentru a detecta erorile din extensiile mysql și mysqli. Următoarele două moduri sunt mai potrivite pentru programarea DRY.

PDO::ERRMODE_WARNING

Acest mod va provoca un avertisment standard și va permite scriptului să continue executarea. Convenabil pentru depanare.

PDO::ERRMODE_EXCEPTION

În majoritatea situațiilor, acest tip de control al execuției scriptului este de preferat. Aruncă o excepție, permițându-vă să gestionați în mod inteligent erorile și să ascundeți informațiile sensibile. Ca, de exemplu, aici:
# conectați-vă la baza de date încercați ( $DBH = PDO nou ("mysql:host=$host;dbname=$dbname", $user, $pass); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION) ; # La naiba! am tastat DELECT în loc de $DBH->prepare("DELECT name FROM people")->execute( ) catch(PDOException $e) ( echo "Houston, avem probleme."; file_put_contents(); „PDOErrors” .txt”, $e->getMessage(), FILE_APPEND); )
Există o eroare de sintaxă în expresia SQL care va arunca o excepție. Putem înregistra detaliile erorii într-un fișier jurnal și putem sugera utilizatorului în limbaj uman că s-a întâmplat ceva.

Inserați și actualizați

Inserarea de date noi și actualizarea datelor existente sunt unele dintre cele mai comune operațiuni ale bazei de date. În cazul DOP, acest proces constă de obicei din două etape. (Secțiunea următoare se referă atât la UPDATE, cât și la INSERT)


Un exemplu banal de inserare de date noi:
# STH înseamnă "Statement Handle" $STH = $DBH->prepare ("INSERT INTO folks (first_name) values ​​​​("Cathy")"); $STH->execute();
De fapt, puteți face același lucru cu o singură metodă exec(), dar metoda în doi pași oferă toate beneficiile instrucțiunilor pregătite. Acestea ajută la protejarea împotriva injecțiilor SQL, așa că este logic să le folosiți chiar și pentru o interogare unică.

Declarații pregătite

Utilizarea instrucțiunilor pregătite întărește protecția împotriva injecțiilor SQL.

O instrucțiune Prepared este o instrucțiune SQL pre-compilată care poate fi executată în mod repetat, trimițând doar seturi diferite de date către server. Un avantaj suplimentar este că este imposibil să se efectueze injecția SQL prin datele utilizate în substituenți.

Mai jos sunt trei exemple de declarații pregătite.
# fără substituenți - ușa către injecțiile SQL este deschisă! $STH = $DBH->prepare("INSERT INTO folks (nume, adresă, oraș) valori ($nume, $adresă, $oraș)"); # substituenți fără nume $STH = $DBH->prepare ("INSERT INTO folks (nume, adresă, oraș) valori (?, ?, ?)"); # substituenți numiți $STH = $DBH->prepare ("INSERT INTO folks (nume, adresă, oraș) valori (:name, :addr, :city)");
Primul exemplu este aici doar pentru comparație și ar trebui evitat. Diferența dintre substituenții fără nume și cei cu nume este modul în care transferați datele către instrucțiunile pregătite.

Substituenți fără nume

# atribuiți variabile fiecărui substituent, cu indici de la 1 la 3 $STH->bindParam(1, $name); $STH->bindParam(2, $adr); $STH->bindParam(3, $oraș); # introduceți o linie $name = "Daniel" $addr = "1 Wicked Way"; $oraș = „Arlington Heights”; $STH->execute(); # introduceți o altă linie, cu date diferite $name = "Steve" $addr = "5 Circle Drive"; $oraș = „Schaumburg”; $STH->execute();
Aici sunt doi pași. Pe primul, atribuim variabile tuturor substituenților (liniile 2-4). Apoi atribuim valori acestor variabile și executăm interogarea. Pentru a trimite un nou set de date, pur și simplu modificați valorile variabilei și rulați din nou cererea.

Dacă expresia dvs. SQL are mulți parametri, atunci alocarea unei variabile fiecăruia este foarte incomod. În astfel de cazuri, puteți stoca datele într-o matrice și le puteți transmite:
# setul de date îl vom introduce $data = array("Cathy", "9 Dark and Twisty Road", "Cardiff"); $STH = $DBH->prepare("INSERT INTO folks (nume, adresa, oraș) valori (?, ?, ?)"); $STH->execute($date);
$data vor fi inserate în locul primului substituent, $data în locul celui de-al doilea etc. Dar aveți grijă: dacă indexurile dvs. sunt încurcate, acest lucru nu va funcționa.

Substituenți numiți

# primul argument este numele substituentului # începe de obicei cu două puncte # deși funcționează fără ele $STH->bindParam(":name", $name);
Aici puteți trece și o matrice, dar trebuie să fie asociativă. Cheile ar trebui să fie, după cum ați putea ghici, numele substituenților.
# datele pe care le introducem $data = array("name" => "Cathy", "addr" => "9 Dark and Twisty", "city" => "Cardiff"); $STH = $DBH->prepare("INSERT INTO folks (nume, adresă, oraș) valori (:name, :addr, :city)"); $STH->execute($date);
Una dintre avantajele utilizării substituenților numiți este abilitatea de a insera obiecte direct în baza de date dacă numele proprietăților se potrivesc cu numele parametrilor. De exemplu, puteți introduce date astfel:
# clasă pentru o persoană de clasă obiect simplă ( public $nume; public $adresă; public $oraș; funcția __construct($n,$a,$c) ( $this->name = $n; $this->addr = $ a ; $this->city = $c ) # asa mai departe... ) $cathy = new person("Cathy","9 Dark and Twisty","Cardiff"); # și aici este partea interesantă $STH = $DBH->prepare ("INSERT INTO folks (name, addr, city) values ​​​​(:name, :addr, :city)"); $STH->execute((matrice)$cathy);
Convertirea unui obiect într-o matrice în timpul execute() face ca proprietățile să fie tratate ca chei de matrice.

Eșantionarea datelor



Datele pot fi preluate folosind metoda ->fetch(). Înainte de a o apela, este recomandabil să indicați în mod explicit sub ce formă le solicitați. Există mai multe opțiuni:
  • PDO::FETCH_ASSOC: returnează o matrice cu nume de coloane ca chei
  • PDO::FETCH_BOTH (implicit): returnează o matrice cu indecși atât sub formă de nume de coloane, cât și de numere de serie ale acestora
  • PDO::FETCH_BOUND: atribuie valori de coloană variabilelor corespunzătoare specificate folosind metoda ->bindColumn().
  • PDO::FETCH_CLASS: atribuie valori de coloană proprietăților corespunzătoare ale clasei specificate. Dacă nu există nicio proprietate pentru o coloană, aceasta va fi creată
  • PDO::FETCH_INTO: actualizează o instanță existentă a clasei specificate
  • PDO::FETCH_LAZY: combină PDO::FETCH_BOTH și PDO::FETCH_OBJ
  • PDO::FETCH_NUM: returnează o matrice cu chei ca numere de coloană
  • PDO::FETCH_OBJ: returnează un obiect anonim cu proprietăți corespunzătoare numelor de coloană
În practică, veți avea nevoie de obicei de trei: FETCH_ASSOC, FETCH_CLASS și FETCH_OBJ. Pentru a specifica formatul datelor, utilizați următoarea sintaxă:
$STH->setFetchMode(PDO::FETCH_ASSOC);
De asemenea, îl puteți seta direct când apelați metoda ->fetch().

FETCH_ASSOC

Acest format creează o matrice asociativă cu nume de coloane ca indici. Ar trebui să fie familiar celor care folosesc extensiile mysql/mysqli.
# deoarece aceasta este o interogare obișnuită fără substituenți, # puteți utiliza imediat metoda query() $STH = $DBH->query("SELECT name, address, city from folks"); # setați modul de preluare $STH->setFetchMode(PDO::FETCH_ASSOC); while($row = $STH->fetch()) ( echo $row["nume"] . "\n"; echo $row["adresa"] . "\n"; echo $row["oraș"] . "\n" ;
Bucla while() va itera prin întregul rezultat al interogării.

FETCH_OBJ

Acest tip de achiziție de date creează o instanță a clasei std pentru fiecare rând.
# creați o interogare $STH = $DBH->query("SELECT numele, adresa, orașul de la oameni"); # selectați modul de preluare $STH->setFetchMode(PDO::FETCH_OBJ); # imprimați rezultatul while($row = $STH->fetch()) ( echo $row->name . "\n"; echo $row->addr . "\n"; echo $row->city . " \ n"; )

FETCH_CLASS

Când utilizați fetch_class, datele sunt scrise în instanțe ale clasei specificate. În acest caz, valorile sunt atribuite proprietăților obiectului ÎNAINTE de a apela constructorul. Dacă proprietățile cu nume care se potrivesc cu numele coloanelor nu există, acestea vor fi create automat (cu domeniul public).

Dacă datele dumneavoastră necesită prelucrare obligatorie imediat după ce sunt primite din baza de date, acestea pot fi implementate în constructorul clasei.

De exemplu, să luăm o situație în care trebuie să ascundeți o parte din adresa de reședință a unei persoane.
clasa persoana_secreta ( public $nume; public $adresa; public $oras; public $alte_date; function __construct($altul = "") ( $this->addr = preg_replace("//", "x", $this-> addr); $aceasta->alte_date = $altele;
La crearea unui obiect, toate literele latine mici trebuie înlocuite cu x. Să verificăm:
$STH = $DBH->query("SELECT numele, adresa, orasul de la oameni"); $STH->setFetchMode(PDO::FETCH_CLASS, "persoana_secreta"); while($obj = $STH->fetch()) ( echo $obj->addr; )
Dacă adresa din baza de date arată ca „5 Rosebud”, atunci rezultatul va fi „5 Rxxxxxx”.

Desigur, uneori veți dori ca constructorul să fie numit ÎNAINTE de a atribui valori. PDO permite și acest lucru.
$STH->setFetchMode(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, „persoană_secretă”);
Acum că ați completat exemplul anterior cu o opțiune suplimentară (PDO::FETCH_PROPS_LATE), adresa nu va fi modificată, deoarece nu se întâmplă nimic după ce valorile sunt scrise.

În cele din urmă, dacă este necesar, puteți transmite argumente direct constructorului atunci când creați obiectul:
$STH->setFetchMode(PDO::FETCH_CLASS, "persoana_secreta", array("lucruri"));
Puteți chiar să transmiteți argumente diferite fiecărui obiect:
$i = 0; while($rowObj = $STH->fetch(PDO::FETCH_CLASS, "secret_person", array($i))) ( // face ceva $i++; )

Alte metode utile

Deși acest articol nu poate (și nu încearcă) să acopere fiecare aspect al lucrului cu PDO (este un modul uriaș!), următoarele câteva caracteristici nu pot fi omise fără mențiuni.
$DBH->lastInsertId();
Metoda ->lastInsertId() returnează id-ul ultimei înregistrări inserate. Este de remarcat faptul că este întotdeauna apelat pe un obiect de bază de date (numit $DBH în acest articol), și nu pe un obiect cu o expresie ($STH).
$DBH->exec("DELETE FROM folks WHERE 1"); $DBH->exec("SET time_zone = "-8:00"");
Metoda ->exec() este folosită pentru operațiunile care nu returnează alte date decât numărul de înregistrări afectate de acestea.
$safe = $DBH->quote($nesigur);
Metoda ->quote() plasează ghilimele în șir de date, astfel încât să fie sigur să le folosiți în interogări. Util dacă nu folosiți declarații pregătite.
$rows_afectated = $STH->rowCount();
Metoda ->rowCount() returnează numărul de înregistrări care au participat la operație. Din păcate, această funcție nu a funcționat cu interogări SELECT până la PHP 5.1.6. Dacă nu este posibilă actualizarea versiunii PHP, numărul de înregistrări poate fi obținut astfel:
$sql = "SELECTARE COUNT(*) FROM folks"; if ($STH = $DBH->query($sql)) ( # verificați numărul de înregistrări dacă ($STH->fetchColumn() > 0) ( # faceți o selecție completă aici deoarece datele au fost găsite! ) else ( # imprimați un mesaj că nu au fost găsite date care să satisfacă cererea) )

Concluzie

Sper că acest material îi va ajuta pe unii dintre voi să migreze din extensiile mysql și mysqli.