Hoe PDO te configureren en te gebruiken voor databasetoegang onder Linux

  • George Richardson
  • 0
  • 4024
  • 844
>

Doelstelling

Leer hoe u PDO configureert en gebruikt voor databasetoegang: van foutmodi tot ophaalmethoden.

Voorwaarden

  • Een standaardkennis van MySQL en mysql opdrachtregelclient;
  • Bekend zijn met de fundamentele concepten van Object Oriented Programming
  • PHP> = 5.1
  • Zorg voor een werkende MySQL / MariaDB-database

Moeilijkheidsgraad

MEDIUM

Conventies

  • # - vereist dat gegeven linux-commando's worden uitgevoerd met root-privileges, hetzij direct als rootgebruiker, hetzij door gebruik van sudo opdracht
  • $ - vereist dat gegeven linux-commando's worden uitgevoerd als een gewone niet-geprivilegieerde gebruiker

Invoering

PDO is een afkorting voor PHP-gegevensobjecten: het is een PHP-extensie voor interactie met databases door het gebruik van objecten. Een van zijn sterke punten ligt in het feit dat het niet strikt gebonden is aan een bepaalde database: de interface biedt een gemeenschappelijke manier om toegang te krijgen tot verschillende omgevingen, waaronder:
  • MySQL
  • SQLite
  • PostgreSQL
  • Microsoft SQL Server
Deze gids is bedoeld om een ​​vrij compleet overzicht van PDO te geven, waarbij de lezer stap voor stap wordt begeleid van het tot stand brengen van een verbinding met de database tot de keuze van de meest geschikte ophaalmodus, laat zien hoe voorbereide verklaringen kunnen worden gemaakt en beschrijft de mogelijke foutmodi..

Maak een testdatabase en -tabel

Het eerste dat we gaan doen, is een database maken voor deze tutorial:
DATABASE MAKEN solar_system; VERLEENT ALLE PRIVILEGES OP solar_system. * AAN 'testuser' @ 'localhost' GEÏDENTIFICEERD DOOR 'testpassword'; 
We hebben de gebruiker toegestaan testgebruiker alle privileges op de zonnestelsel database, met behulp van testwachtwoord als wachtwoord. Laten we nu een tabel maken en deze vullen met wat gegevens (geen astronomische nauwkeurigheid bedoeld):
GEBRUIK solar_system; CREATE TABLE planets (id TINYINT (1) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (id), naam VARCHAR (10) NOT NULL, kleur VARCHAR (10) NOT NULL); VOEG IN planeten (naam, kleur) WAARDEN ('aarde', 'blauw'), ('mars', 'rood'), ('jupiter', 'vreemd'); 

DSN: naam van gegevensbron

Nu we een database hebben, moeten we een DSN. DSN staat voor Naam gegevensbron, en het is eigenlijk een set informatie die nodig is om verbinding te maken met de database, weergegeven in de vorm van een string. De syntaxis kan verschillen afhankelijk van de database waarmee u verbinding wilt maken, maar aangezien we interactie hebben met MySQL / MariaDB, zullen we het volgende bieden:
  • Het type stuurprogramma dat voor de verbinding moet worden gebruikt
  • De hostnaam van de machine die de database host
  • De poort die moet worden gebruikt voor de verbinding (optioneel)
  • De naam van de database
  • De karakterset (optioneel)
Het formaat van de string zou in ons geval het volgende zijn (we gaan het opslaan in de $ dsn variabele):
$ dsn = "mysql: host = localhost; port = 3306; dbname = solar_system; charset = utf8"; 
Allereerst hebben we de database voorvoegsel. In dit geval, omdat we verbinding maken met een MySQL / MariaDB-database, hebben we mysql. Vervolgens hebben we het voorvoegsel van de rest van de string gescheiden door een dubbele punt en elk van de andere secties door een puntkomma.
In de volgende twee secties hebben we de hostnaam van de machine waarop de database wordt gehost en het haven te gebruiken voor de verbinding. Als de laatste niet wordt verstrekt, wordt de standaard gebruikt, wat in dit geval het geval is 3306. Onmiddellijk nadat we het database naam, en daarna de tekenset gebruiken.

Creëren van het PDO-object

Nu onze DSN klaar is, gaan we het PDO-object. De PDO-constructor neemt de dsn-string als eerste parameter, de naam van de gebruiker in de database als tweede parameter, het wachtwoord als derde en optioneel een reeks opties als de vierde:
$ options = [PDO :: ATTR_ERRMODE => PDO :: ERRMODE_EXCEPTION, PDO :: ATTR_DEFAULT_FETCH_MODE => PDO :: FETCH_ASSOC]; $ pdo = nieuwe PDO ($ dsn, 'testuser', 'testpassword', $ options); 
De opties kunnen echter ook worden gespecificeerd nadat het object is gebouwd, via de SetAttribute () methode:
$ pdo-> SetAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); 

PDO-gedrag instellen op fouten

Laten we eens kijken naar enkele van de beschikbare opties voor PDO :: ATTR_ERRMODE. Deze optie is erg belangrijk, omdat het PDO-gedrag bij fouten definieert. Mogelijke opties zijn:

PDO :: ERRMODE_SILENT

Dit is de standaard. PDO stelt alleen de foutcode en foutmelding in. Ze kunnen worden opgehaald met behulp van de foutcode() en errorInfo () methoden.

PDO :: ERRMODE_EXCEPTION

Dit is naar mijn mening de aanbevolen. Met deze optie zal PDO, naast het instellen van de foutcode en info, een PDO-uitzondering, wat de scriptstroom zal breken, en het is vooral handig in het geval van BOB-transacties (we gaan later in deze tutorial kijken welke transacties er zijn).

PDO :: ERRMODE_WARNING

Met deze optie stelt PDO de foutcode en info in als geïndexeerd PDO :: ERRMODE_SILENT, maar zal ook een WAARSCHUWING, wat de stroom van het script niet zal breken.

Standaard ophaalmodus instellen

Een andere belangrijke instelling kan worden opgegeven via de PDO :: DEFAULT_FETCH_MODE. constante. Hiermee kunt u de standaard ophaalmethode specificeren die moet worden gebruikt bij het ophalen van resultaten van een query. Dit zijn de meest gebruikte opties:

PDO :: FETCH_BOTH:

Dit is de standaard. Hiermee wordt het resultaat dat wordt opgehaald door een ophaalquery zowel geïndexeerd op integer als op kolomnaam. Het toepassen van deze ophaalmodus bij het ophalen van een rij uit de planettentabel zou ons dit resultaat geven:

$ stmt = $ pdo-> query ("SELECTEER * VAN planeten"); $ results = $ stmt-> fetch (PDO :: FETCH_BOTH); 
 Matrix ([id] => 1 [0] => 1 [naam] => aarde [1] => aarde [kleur] => blauw [2] => blauw) 

PDO :: FETCH_ASSOC:

Met deze optie wordt het resultaat opgeslagen in een associatieve array waarin elke sleutel de naam van de kolom is en elke waarde de overeenkomstige waarde in een rij:

$ stmt = $ pdo-> query ("SELECTEER * VAN planeten"); $ results = $ stmt-> fetch (PDO :: FETCH_ASSOC);
 Matrix ([id] => 1 [naam] => aarde [kleur] => blauw) 

BOB :: FETCH_NUM

Deze ophaalmodus retourneert de opgehaalde rij in een 0-geïndexeerde array:

 Array ([0] => 1 [1] => aarde [2] => blauw) 

PDO :: FETCH_COLUMN

Deze ophaalmethode is handig bij het ophalen van alleen de waarden van een kolom en retourneert alle resultaten in een gewone, eendimensionale array. Bijvoorbeeld deze vraag:

$ stmt = $ pdo-> query ("SELECTEER naam UIT planeten");
Zou dit resultaat retourneren:
 Array ([0] => aarde [1] => mars [2] => jupiter) 

PDO :: FETCH_KEY_PAIR

Deze ophaalmethode is handig bij het ophalen van de waarden van slechts 2 kolommen. Het retourneert de resultaten in de vorm van een associatieve array waarin de waarden die uit de database zijn opgehaald voor de eerste opgegeven kolom in de query, worden gebruikt als de arraysleutels, terwijl de waarden die worden opgehaald voor de tweede kolom, de associatieve matrixwaarden:

$ stmt = $ pdo-> query ("SELECTEER naam, kleur VAN planeten"); $ result = $ stmt-> fetchAll (PDO :: FETCH_KEY_PAIR); 
Zou terugbrengen:
 Array ([earth] => blauw [mars] => rood [jupiter] => vreemd) 

BOB :: FETCH_OBJECT:

Bij gebruik van de PDO :: FETCH_OBJECT constant, een anoniem object wordt gemaakt voor elke opgehaalde rij. De (openbare) eigenschappen worden genoemd naar de kolommen en de queryresultaten worden gebruikt als hun waarden. Het toepassen van deze ophaalmodus op dezelfde query hierboven zou ons een resultaat opleveren in de vorm:

$ results = $ stmt-> fetch (PDO :: FETCH_OBJ);
 stdClass-object ([naam] => aarde [kleur] => blauw) 

PDO :: FETCH_CLASS:

Deze ophaalmodus zal, net als de bovenstaande, de waarde van de kolommen toewijzen aan de eigenschappen van een object, maar in dit geval moeten we een bestaande klasse specificeren die moet worden gebruikt om het object te maken. Laten we het demonstreren, eerst gaan we een klas maken:

klasse Planet private $ naam; privé $ kleur; openbare functie setName ($ planet_name) $ this-> name = $ planet_name;  openbare functie setColor ($ planet_color) $ this-> color = $ planet_color;  openbare functie getName () return $ this-> name;  publieke functie getColor () return $ this-> color;  
Negeer de naïviteit van de bovenstaande code en merk op dat de eigenschappen van de klasse Planet dat wel zijn privaat en de klasse heeft geen constructor. Laten we nu proberen de resultaten op te halen.
Tijdens gebruik ophalen () met PDO :: FETCH_CLASS je moet de setFechMode () methode op het instructieobject voordat u probeert de gegevens op te halen, bijvoorbeeld:
$ stmt = $ pdo-> query ("SELECTEER naam, kleur VAN planeten"); $ stmt-> setFetchMode (PDO :: FETCH_CLASS, 'Planet');
We hebben de ophaaloptie constant opgegeven PDO :: FETCH_CLASS als het eerste argument van de methode setFetchMode (), en de naam van de klasse die moet worden gebruikt om het object te maken (in dit geval 'Planet') als de tweede. Nu lopen we:
$ planet = $ stmt-> fetch ();
Er zou een Planet-object moeten zijn gemaakt:
var_dump ($ planeet);
 Planeet Object ([naam: Planeet: privé] => aarde [kleur: Planeet: privé] => blauw) 
Merk op hoe de waarden die zijn opgehaald als gevolg van de query, zijn toegewezen aan de overeenkomstige eigenschappen van het object, zelfs als ze privé zijn.

Eigenschappen toewijzen na de constructie van het object

De planeetklasse heeft geen expliciete constructor gedefinieerd, dus geen problemen bij het toewijzen van de eigenschappen; maar wat als de klasse een constructor had waarin de eigenschap werd toegewezen of gemanipuleerd? Omdat de waarden worden toegewezen voordat de constructor wordt aangeroepen, zouden ze zijn overschreven.
PDO helpt het FETCH_PROPS_LATE constante: bij gebruik worden de waarden toegewezen aan de eigenschappen na het object is geconstrueerd. Bijvoorbeeld:
klasse Planet private $ naam; privé $ kleur; openbare functie __construct ($ naam = maan, $ kleur = grijs) $ this-> naam = $ naam; $ this-> color = $ color;  publieke functie setName ($ planet_name) $ this-> name = $ planet_name;  openbare functie setColor ($ planet_color) $ this-> color = $ planet_color;  openbare functie getName () return $ this-> name;  publieke functie getColor () return $ this-> color; 
We hebben onze Planet-klasse aangepast en een constructor opgeleverd die twee argumenten nodig heeft: de eerste is naam en de tweede is kleur. Die argumenten hebben een standaardwaarde van respectievelijk maan en grijs: dit betekent dat als er geen waarden expliciet worden opgegeven, dit de standaardwaarden zijn die zijn toegewezen.
In dit geval, als we geen gebruik maken van FETCH_PROPS_LATE, ongeacht de waarden die uit de database worden opgehaald, de eigenschappen zullen altijd de standaardwaarden hebben, omdat ze worden overschreven wanneer het object wordt geconstrueerd. Laten we het verifiëren. Eerst voeren we de query uit:
$ stmt = $ pdo-> query ("SELECTEER naam, kleur FROM solar_system WHERE name = 'earth'"); $ stmt-> setFetchMode (PDO :: FETCH_CLASS, 'Planet'); $ planet = $ stmt-> fetch ();
Dan dumpen we het Planeet object en controleer welke waarden zijn eigenschappen hebben:
var_dump ($ planeet); object (Planet) # 2 (2) ["name": "Planet": private] => string (4) "moon" ["color": "Planet": private] => string (4) "grijs" 
Zoals verwacht zijn de waarden die uit de database zijn opgehaald, overschreven door de standaardinstellingen. Nu laten we zien hoe dit probleem kan worden opgelost door FETCH_PROPS_LATE (de vraag is hetzelfde als hierboven):
$ stmt-> setFetchMode (PDO :: FETCH_CLASS | PDO :: FETCH_PROPS_LATE, 'Planet'); $ planet = $ stmt-> fetch (); var_dump ($ planeet); object (Planet) # 4 (2) ["name": "Planet": private] => string (5) "earth" ["color": "Planet": private] => string (4) "blauw" 
Eindelijk kregen we de gewenste resultaten. Maar wat als de klassenconstructor geen standaardwaarden heeft en deze moeten worden opgegeven? Simpel: we kunnen de constructorparameters specificeren in de vorm van een array als derde argument, na de klassenaam, in de setFetchMode () methode. Laat bijvoorbeeld de constructor wijzigen:
klasse Planet private $ naam; privé $ kleur; openbare functie __construct ($ naam, $ kleur) $ this-> name = $ naam; $ this-> color = $ color;  […]
De constructorargumenten zijn nu verplicht, dus we zouden het volgende uitvoeren:
$ stmt-> setFetchMode (PDO :: FETCH_CLASS | PDO :: FETCH_PROPS_LATE, 'Planet', ['moon', 'grey']);
In dit geval dienen de door ons verstrekte parameters alleen als standaardwaarden, die nodig zijn om het object foutloos te initialiseren: ze worden overschreven door de waarden die uit de database worden opgehaald.

Meerdere objecten ophalen

Het is natuurlijk mogelijk om meerdere resultaten als objecten op te halen, ofwel met ophalen () methode binnen een while-lus:
while ($ planet = $ stmt-> fetch ()) // doe dingen met de resultaten 
of door alle resultaten in één keer op te halen. Gebruik in dit geval, zoals hierboven vermeld, de fetchAll () methode, je hoeft de fetch-modus niet op te geven voordat je de methode zelf aanroept, maar op het moment dat je het aanroept:
$ stmt-> fetchAll (PDO :: FETCH_CLASS | PDO_FETCH_PROPS_LATE, 'Planet', ['moon', 'grey']); 

PDO :: FETCH_INTO

Met deze ophaalmethode ingesteld, maakt PDO geen nieuw object, maar werkt het de eigenschappen van een bestaand object bij, maar alleen als dat zo is openbaar, of als u de __set magische methode in het object.

Opgesteld versus directe verklaringen

PDO heeft twee manieren om zoekopdrachten uit te voeren: de ene is de directe, eenstaps-manier. De andere, veiliger is om te gebruiken voorbereide verklaringen.

Directe vragen

Bij het gebruik van directe zoekopdrachten zijn er twee hoofdmethoden: vraag () en exec (). De eerste retourneert een PDOStatemnt object dat u kunt gebruiken om toegang te krijgen tot resultaten via het ophalen () of fetchAll () methoden: je gebruikt het voor een instructie die geen tabel wijzigt, zoals SELECTEER.
De laatste retourneert in plaats daarvan het aantal rijen dat door de query is gewijzigd: we gebruiken het voor instructies die rijen wijzigen, zoals INVOEGEN, VERWIJDEREN of BIJWERKEN. Directe instructies mogen alleen worden gebruikt als er geen variabelen in de query zijn en u er absoluut op vertrouwt dat het veilig is en correct ontsnapt.

Opgestelde verklaringen

PDO ondersteunt ook tweetraps, voorbereide verklaringen: dit is handig bij het gebruik van variabelen in de query, en het is in het algemeen veiliger, omdat de bereiden() methode zal al het nodige ontsnappen voor ons uitvoeren. Laten we eens kijken hoe variabelen worden gebruikt. Stel dat we de eigenschappen van een Planet-object willen invoegen in het Planeten tafel. Eerst zouden we de vraag voorbereiden:
$ stmt = $ pdo-> prepar ("VOEG IN planeten (naam, kleur) WAARDEN (?,?)"); 
Zoals eerder gezegd, zouden we eerst de bereiden() methode die de sql-query als argument aanneemt, met behulp van tijdelijke aanduidingen voor de variabelen. Tijdelijke aanduidingen kunnen van twee typen zijn:

Positionele tijdelijke aanduidingen

Tijdens gebruik ? positionele tijdelijke aanduidingen kunnen we beknoptere code krijgen, maar we moeten de waarden die moeten worden vervangen in dezelfde volgorde van de kolomnamen opgeven, in een array die wordt opgegeven als het argument voor de uitvoeren () methode:

$ stmt-> execute ([$ planet-> name, $ planet-> color]); 

Benoemde tijdelijke aanduidingen

Gebruik makend van benoemde tijdelijke aanduidingen, we hoeven een bepaalde volgorde niet te respecteren, maar we gaan meer uitgebreide code maken. Bij het uitvoeren van het uitvoeren () methode moeten we de waarden in de vorm van een associatieve array waarin elke sleutel de naam is van de gebruikte tijdelijke aanduiding en de bijbehorende waarde de waarde die in de query moet worden vervangen. De bovenstaande zoekopdracht zou bijvoorbeeld worden:

$ stmt = $ pdo-> prepar ("VOEG IN planeten (naam, kleur) WAARDEN (: naam,: kleur)"); $ stmt-> execute (['name' => $ planet-> name, 'color' => $ planet-> color]); 
De methoden voorbereiden en uitvoeren kunnen zowel worden gebruikt bij het uitvoeren van query's die gegevens wijzigen of alleen ophalen uit de database. In het eerste geval gebruiken we de ophaalmethoden die we hierboven zagen om de gegevens op te halen, terwijl we in het laatste geval het aantal betrokken rijen kunnen achterhalen met behulp van de aantal rijen() methode.

De methoden bindValue () en bindParam ()

Om de te vervangen waarden in de query op te geven, kunnen we ook de bindValue () en bindParam () methoden. De eerste bindt de waarde van de opgegeven variabele aan de gerelateerde positionele of benoemde tijdelijke aanduiding die wordt gebruikt bij het voorbereiden van de query. Met behulp van het bovenstaande voorbeeld zouden we hebben gedaan:
$ stmt-> bindValue ('naam', $ planet-> naam, PDO :: PARAM_STR); 
We binden de waarde van $ planet-> naam naar de :naam tijdelijke aanduiding. Merk op dat als we zowel bindValue () als bindParam () methoden gebruiken, we als derde argument de type van de variabele, in dit geval met behulp van de gerelateerde PDO-constante PDO :: PARAM_STR.
Gebruik makend van bindParam (), in plaats daarvan kunnen we de variabele binden aan de gerelateerde tijdelijke aanduiding die wordt gebruikt bij het voorbereiden van de query. Merk op dat in dit geval de variabele is gebonden aan referentie, en de waarde wordt alleen vervangen door de tijdelijke aanduiding op het moment dat de uitvoeren () methode heet het. De syntaxis is hetzelfde als hierboven:
$ stmt-> bindParam ('naam', $ planet-> naam, PDO :: PARAM_STR) 
We hebben de $ planet-> name variabele gebonden aan de :naam placeholder, niet de huidige waarde! Zoals hierboven vermeld, zal de conversie worden uitgevoerd net wanneer de uitvoeren () methode wordt aangeroepen, dus de tijdelijke aanduiding wordt vervangen door de waarde die de variabele op dat moment heeft.

BOB-transacties

Transacties bieden een manier om de consistentie te behouden bij het verzenden van meerdere query's. Alle zoekopdrachten worden in een "batch" gedaan en alleen in de database opgenomen als ze allemaal succesvol zijn. Transacties werken niet in alle databases en niet voor alle sql constructies, omdat sommige van hen een impliciete commit veroorzaken (volledige lijst hier)
Stel je met een extreem en vreemd voorbeeld voor dat de gebruiker een lijst met planeten moet selecteren, en elke keer dat hij een nieuwe selectie indient, wil je de vorige uit de database verwijderen voordat je de nieuwe invoegt. Wat zou er gebeuren als het verwijderen lukt, maar niet het invoegen? We zouden een gebruiker zonder planeten hebben! Typisch is dit hoe transacties worden geïmplementeerd:
$ pdo-> beginTransaction (); probeer $ stmt1 = $ pdo-> exec ("DELETE FROM planets"); $ stmt2 = $ pdo-> prepar ("VOEG IN planeten (naam, kleur) WAARDEN (?,?)"); foreach ($ planets as $ planet) $ stmt2-> execute ([$ planet-> getName (), $ planet-> getColor ()]);  $ pdo-> commit ();  catch (PDOException $ e) $ pdo-> rollBack (); 
Allereerst de beginTransaction () methode van het PDO-object schakelt de autocommit van de query uit, en binnen een try-catch-blok worden de queries uitgevoerd in de gewenste volgorde. Op dit punt als nee PDO-uitzondering wordt verhoogd, worden de vragen vastgelegd met de plegen () methode, anders via de terugrollen() methode, worden de transacties teruggedraaid en wordt autocommit hersteld.
Op deze manier is er altijd consistentie bij het geven van meerdere vragen. Het is vrij duidelijk dat u BOB-transacties alleen kunt gebruiken als de PDO :: ATTR_ERRMODE staat op PDO :: ERRMODE_EXCEPTION.



Niemand heeft nog op dit artikel gereageerd.

Een verzameling nuttige informatie over het Linux-besturingssysteem en nieuwe technologieën
Nieuwe artikelen, praktische tips, gedetailleerde recensies en handleidingen. Voel je thuis in de wereld van het Linux-besturingssysteem