PDO - Verbinden met verschillende databases

Door Joren de Wit, 14 jaar geleden, 23.628x bekeken

Gebruik de PDO extensie om verbindingen met verschillende database systemen te onderhouden.

Gesponsorde koppelingen

Inhoudsopgave

  1. Inleiding
  2. Gebruik van de PDO extensie
  3. Uitvoeren van queries
  4. Foutafhandeling
  5. Prepared statements
  6. Transacties
  7. Slotwoord en referenties

 

Er zijn 45 reacties op 'Pdo verbinden met verschillende databases'

PHP hulp
PHP hulp
0 seconden vanaf nu
 

Gesponsorde koppelingen
- -
- -
14 jaar geleden
 
0 +1 -0 -1
Blanche, geweldig man!

Iki heb een deel gelezen, maar ik vraag me af (misschien stond het ook wel in de tutorial), wat raad je aan voor MySQL: PDO of MySQLi?
Joren de Wit
Joren de Wit
14 jaar geleden
 
0 +1 -0 -1
PDO is voornamelijk interessant als je meerdere databases wilt gebruiken of je je code compatible met een andere database wilt houden. Bijvoorbeeld als je in de toekomst nog eens van database wilt switchen.

De MySQLi extensie biedt je meer mysql specifieke methodes die je kunt gebruiken. Deze ontbreken logischerwijs bij PDO aangezien die extensie rekening moet houden met meerdere database systemen.

Als je dus alleen met MySQL werkt, zou ik voor MySQLi gaan.
Frank -
Frank -
14 jaar geleden
 
0 +1 -0 -1
Quote:
Nooit meer last van incompatibiliteit van je scripts met een andere database, het is namelijk nog maar een kwestie van 1 regeltje code veranderen.
Tja, het maken van de verbinding, het verwerken van de resultaten en de foutafhandeling, die code (php-code wel te verstaan) is inderdaad compatible. Voor de SQL gaat dat helaas niet op, ga bv. maar eens met datums rekenen in MySQL of in PostgreSQL. Dat zijn totaal verschillende functies! Ook voor de datatypes gaat dit op, pgSQL kent meer datatypes en in pgSQL kun je ook je eigen datatypes aanmaken.

Het is mogelijk om vrijwel 100% compatibliteit te krijgen, maar dan zul je vrijwel alle functies van de database overboord moeten gooien en standaard datatypes moeten gebruiken. Alleen simpele queries kun je dan nog uitvoeren, de rest van de bewerkingen van de data zul je zelf moeten bouwen. En of je dat wilt? Ik zou er niet aan beginnen, ik laat graag de database een hoop werk voor mij doen.

Desondanks is PDO een uitstekende toepassing. Mocht je van database willen veranderen, dan hoef je uitsluitend de SQL aan te passen.

Ps. Wederom een fraaie tut! Kun je deze tut's niet gaan bundelen en als boekwerkje uit gaan geven? Desnoods als pdf en uitgegeven onder de creative commons.
Bo az
Bo az
14 jaar geleden
 
0 +1 -0 -1
Iets belangrijks om op te wijzen:
Quote:
If your application does not catch the exception thrown from the PDO constructor, the default action taken by the zend engine is to terminate the script and display a back trace. This back trace will likely reveal the full database connection details, including the username and password. It is your responsibility to catch this exception, either explicitly (via a catch statement) or implicitly via set_exception_handler().

Plaats dus altijd(!) een try / catch statement om de constructor.

Zoals gezegd, je php code hoef je niet aan te passen als je van RDBMS wisselt, zelfs fout codes zijn universeel, zo is de normale error code voor een overschrijding van een unique constraint in MySQL 1062, de PDO code is: 23000

Blanche, erg nette tutorial!
Joren de Wit
Joren de Wit
14 jaar geleden
 
0 +1 -0 -1
Bedankt voor de feedback, heb even wat puntjes aangepast en toegevoegd.

ps. @Frank: misschien wel een leuk idee om zoiets in de toekomst uit te geven. Echter wil ik de tutorials dan nog wel een stuk uitbreiden. Voor nu voldoet het plaatsen op internet :)
Jan geen
Jan geen
14 jaar geleden
 
0 +1 -0 -1
Goede duidelijke uitleg! mooi gedaan.
Pim Vernooij
Pim Vernooij
14 jaar geleden
 
0 +1 -0 -1
Je methode om een prepared statement in te zetten voor meerdere keren (waarbij je je data uit een array haalt), vind ik niet echt mooi. Je kan namelijk ook een array met parameters meegeven aan $stmt->execute()! Voor de rest een mooie tutorial :)

Ik vind het voordeel van PDO voornamelijk dat je in het geval van hergebruik van bijvoorbeeld een framework niet aan een database gebonden bent.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
$stmt
= $db->prepare( "insert into user (name, password, email) values( ?, ?, ? )" );

$user = array( 'Jan', 'querty', 'jan@querty.nl' );
$stmt->execute( $user );

//of:
$users = array(
    array( 'Jan', 'querty', 'jan@querty.nl' ),
    array( 'Jan', 'querty', 'jan@querty.nl' ),
    array( 'Jan', 'querty', 'jan@querty.nl' )
);


foreach( $users as $user ) {
    $stmt->execute( $user );
}

?>


Uiteraard is het ook mogelijk om de named syntax te hanteren:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
<?php
$stmt
= $db->prepare( "insert into user (name, password, email) values( :name, :password, :email )" );
$user = array( ':name' => 'Jan', ':password' => 'querty', ':email' => 'jan@querty.nl' );
$stmt->execute( $user );
?>
Arend a
Arend a
14 jaar geleden
 
0 +1 -0 -1
@Frank: je hebt inderdaad nog incompatiblities tussen databases. Maar het beperkt zich meestal tot het gebruik data en dergelijke. Vaak is het behoorlijk goed dat te ondervangen.

Misschien iets om een universal datum handler class te gebruiken ofzo. Die afhankelijk van wat het gevoerd wordt het omtoverd tot bruikbare resultaten in php? :)
Frank -
Frank -
14 jaar geleden
 
0 +1 -0 -1
@Arend: Dat valt nog tegen, kijk alleen maar eens naar de verschillende datatypes tussen MySQL en PostgreSQL (deze databases ken ik vrij aardig). Mooi voorbeeld is de TIMESTAMP, die is echt totaal anders. MySQL kent infinity en -infinity (oneindig) niet, daar kun je dus mooi de mist in gaan. Een SERIAL en een INT met auto_increment zijn ook 2 totaal verschillende dingen, helemaal omdat auto_increment nog wel eens een nummer opnieuw wil uitgeven.

Verder gebruik je in pgSQL de || om 2 gegevens aan elkaar te plakken, in MySQL is dit een OR en heb je de functie CONCAT() nodig.

Wil je ?cht de flexibiliteit hebben om van de ene database snel over te kunnen stappen naar de andere database, dan zul je altijd een hoop extra PHP werk moeten verzetten. Je kunt er gewoon niet van uitgaan dat iedere database beschikt over dezelfde functies (al dan niet met een andere naam) en dus zul je deze functie in PHP nogmaals moeten gaan bouwen. En dan komt de aap uit de mouw, ik ben liever lui dan moe...

Kortom, ik bouw een flexibel systeem in PHP en pas op verzoek de SQL aan. Daarmee kan ik toch van de kracht van de database gebruik maken en is het niet alleen maar een bak met gegevens maar een echte DBMS.
Joren de Wit
Joren de Wit
14 jaar geleden
 
0 +1 -0 -1
@Pim: daar heb je natuurlijk helemaal gelijk in, dat ben ik helemaal vergeten mee te nemen. Heb hier ook even een voorbeeld van opgenomen in de tutorial. Thanks!
Hipska BE
Hipska BE
14 jaar geleden
 
0 +1 -0 -1
nog 1 iets is mij momenteel onduidelijk.

hoe doe je met PDO een num_rows() ?
is daar een functie voor? of doe je gewoon count($result) ?
Frank -
Frank -
14 jaar geleden
 
0 +1 -0 -1
@Hipska: rowCount() doet de truc!
Lord Niek
Lord Niek
14 jaar geleden
 
0 +1 -0 -1
Blanche: dacht jij zo van: Wat een slechte tuts hebben ze op phphulp, zal ik daar ff verrandering in brengen!?

* en toen waren er 99 super goede tuts geboren *
Joren de Wit
Joren de Wit
14 jaar geleden
 
0 +1 -0 -1
@Niek: tnx voor het compliment. Dit zijn echter allemaal tutorials die ik ooit al eens geschreven had en die ik nu geupdate heb, of waar ik al eens aan begonnen was maar nooit afgemaakt heb.

Nu heb ik eindelijk tijd gevonden om ze eens te updaten en af te maken :)
Robert Deiman
Robert Deiman
14 jaar geleden
 
0 +1 -0 -1
Mooie TuT Blanche, een echte aanwinst voor de site.

Ik heb nog wel een kleine op/ aanmerking. In de code bij voorbeeld 19 kan voor sommigen wat onduidelijkheid ontstaan over de regels 22 - 31 (de foreach) wanneer 1 van de 2 regels of updates nu niet wordt uitgevoerd, krijg je wel de melding dat de Update query niets heeft gedaan. (bij beide zou je dit 2 keer krijgen) Ik denk dat het voor de duidelijkheid verstandiger zou zijn om daar:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
'Er is geen rij geupdate met de naam: '.$naam

Dan zie je ook meteen welke rij niet werd geupdate. (het is maar een kleinigheidje, als je de tut snapt snap je dit ook wel)
Joren de Wit
Joren de Wit
14 jaar geleden
 
0 +1 -0 -1
Voor de duidelijkheid even aangepast :)
Joeri
Joeri
14 jaar geleden
 
0 +1 -0 -1
Amai Blanche, je bent nogal op dreff de laatste tijd.!


!!!! STUK VOOR STUK PRACHTIGE TUTORIALS !!!
Frank -
Frank -
14 jaar geleden
 
0 +1 -0 -1
Er schijnt zelfs een PDO voor PHP versie 4 te zijn... Wellicht dat iemand er wat aan heeft.
Hipska BE
Hipska BE
14 jaar geleden
 
0 +1 -0 -1
@pgFrank jij liegt! rowCount() is geen vervanger van ..._num_rows() maar van ..._affected_rows()

Is er dus een vervanger van ..._num_rows() of is de beste methode count($result); ?
Frank -
Frank -
14 jaar geleden
 
0 +1 -0 -1
@Hipska: 'Liegen' vind ik wel een erg groot woord daar waar het een vergissing betreft...

Je hebt wel gelijk, het betreft de affected-rows. Maar wanneer je dit stuk van de handleiding doorneemt, dan krijg je ook direct een oplossing voor de count.
Hipska BE
Hipska BE
14 jaar geleden
 
0 +1 -0 -1
Het was maar een grapje hoor dat "liegt" :p

Maar die oplossing is toch veel omslachtiger?
Trouwens kunnen alle records gewist zijn tussen die 2 query's dmv een ander script dat gelijktijdig aan het runnen is.
GaMer B
GaMer B
13 jaar geleden
 
0 +1 -0 -1
Ik heb het zo opgelost (num_rows achtig iets):
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
$sql
= "SELECT COUNT(*) AS aantal FROM tabel WHERE id=1";
$results = $db->query($sql);
foreach($results as $row)
{

    $aantal = $row['aantal'];
}

if($aantal > 0)
{

    // Er zijn rijen aanwezig
}
else
{
    // Er zijn geen rijn aanwezig
}[/code]

Maar nog een vraag:
De delete query, gaat die net als de UPDATE query?
Frank -
Frank -
13 jaar geleden
 
0 +1 -0 -1
Quote:
Maar nog een vraag:
De delete query, gaat die net als de UPDATE query?
Gezien jouw kennis zou je toch moeten weten dat een DELETE een andere syntax heeft dan een UPDATE.

Kun je de vraag verduidelijken?
GaMer B
GaMer B
13 jaar geleden
 
0 +1 -0 -1
Ja, dat weet ik wel, maar ook zo:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
<?php
$db
= new PDO('mysql:host=localhost;dbname=test','user','password');

$sql = "DELETE FROM tabel WHERE naam = 'Piet'";
$db->exec($sql);
?>

??
EDIT: Met name de afhandeling
EDIT2: Ik zie hier op PHP.net dit staan:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
<?php
/* Delete all rows from the FRUIT table */
$del = $dbh->prepare('DELETE FROM fruit');
$del->execute();

/* Return number of rows that were deleted */
print("Return number of rows that were deleted:\n");
$count = $del->rowCount();
print("Deleted $count rows.\n");
?>
Joren de Wit
Joren de Wit
13 jaar geleden
 
0 +1 -0 -1
Dat is een mogelijkheid, maar je kunt het ook gewoon doen op de manier die jijzelf al aangeeft. Het voordeel van de exec() methode is dat direct al het aantal gewijzigde rijen teruggegeven wordt. Je hoeft dat dus niet meer te controleren met rowCount().
Ivo van Beek
Ivo van Beek
13 jaar geleden
 
0 +1 -0 -1
Erg mooie tut, alleen zit ik nog met 1 vraag. Ik zit vast met het escapen, als ik pdo->quote gebruik dan weet ik niet 100% zeker of dat veilig is en of dat ongeveer hetzelfde effect geeft als mysql_real_escape_string. Kan iemand me dat uitleggen?
Frank -
Frank -
13 jaar geleden
 
0 +1 -0 -1
@Ivo: Zie de prepared statements, dat is vele malen handiger. Het geeft je 100% controle over de query en de input.
Ivo van Beek
Ivo van Beek
13 jaar geleden
 
0 +1 -0 -1
@pGFrank,

Bedankt voor je reactie! Erg handig, alles wordt al beveiligd voor me:P
Thijs X
Thijs X
13 jaar geleden
 
0 +1 -0 -1
Mooie tutorial, ga gelijk implementeren in mn huidige project maar nog 1 vraag.

Maken jullie elke keer opnieuw een object aan die connectie maak met de DB bij elke query die je uitvoerd?
Of zet je het in een appart bestand die je overal waar nodig include?

En is het nodig om het object de deleten? $db = null; ?
Joren de Wit
Joren de Wit
13 jaar geleden
 
0 +1 -0 -1
Je kunt 1 verbinding gerust meerdere keren gebruiken en dus bijvoorbeeld een bestandje includen waarin je die verbinding aanmaakt. Ook is het niet per se nodig om het object te destroyen. Als een script eindigt wordt het object vanzelf vernietigd en de verbinding gesloten...

Pas als je scripts hebt waar je heel veel database acties uitvoert of waarbij het van belang is dat verschillende gebruikers een verbinding kunnen maken (rechten worden verdeeld op database niveau), zou het voordelig kunnen zijn om meerdere connecties te maken en ze ook weer netjes af te sluiten.
Michael
michael
13 jaar geleden
 
0 +1 -0 -1
Is het niet mogelijk om hibernate met php te koppelen? Ik heb dit gebruikt in Java en het werkte echt perfect. Hoef je ook geen queries meer te maken en kan je de database echt makkelijk overzetten. Ik heb er ooit eens iets over gelezen dat het mogelijk is met PHP. Weten jullie er misschien iets meer van?
Frank -
Frank -
13 jaar geleden
 
0 +1 -0 -1
@Michael: Je bedoelt zoiets als Propel?

Dikke ellende, je verliest met dit soort zaken vrijwel alle pluspunten van een database. Performance is dan ook om te huilen.

Daarnaast is het niet nodig om een (PHP-) programmeur lastig te vallen met queries, geef hem/haar gewoon een API en klaar is kees. De DBA kan dan in de database deze API kan bouwen en beheren, dat zal vele malen sneller en veiliger zijn. Databases als DB2, Oracle, PostgreSQL en SQL Server kennen allemaal de mogelijkheid om met stored procedures, views, etc. te werken. Dat maakt het leven voor de programmeur vele malen eenvoudiger, een simpele query als
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
SELECT * FROM api.procedure(var1, var2, var3);

is echt niet moeilijk te intergreren.
Ericbruggema x
ericbruggema x
13 jaar geleden
 
0 +1 -0 -1
Ik wil wel eens weten waarom je nu niet meer simpel het aantal rows kunt uitlezen zoals met mysql_num_rows, op php.net stond dat je eerst een count moet laten uitvoeren om het aantal records uit te lezen. Of zit ik fout?
Joren de Wit
Joren de Wit
13 jaar geleden
 
0 +1 -0 -1
Je kunt inderdaad een SQL query met COUNT() uitvoeren om het aantal records te bepalen. Ook zou je bijvoorbeeld het resultaat met fetchAll() in een array kunnen zetten en vervolgens de PHP functie count() gebruiken om het aantal records te tellen.
Emmanuel Delay
Emmanuel Delay
12 jaar geleden
 
0 +1 -0 -1
Als het iemand interesseert, ik ben bezig een (wrapper) class aan het maken om wat gemakkelijker dit alles te kunnen toepassen.

Zo'n class maken, is trouwens een goeie oefening om dit alles onder de knie te krijgen.

Mooie tutorial.

Misschien een detail:
In een paar voorbeelden zet je een leeftijd in de database.
Een leeftijd is een afgeleid veld. Geboortedatum zou beter zijn.
Maar, het is dus maar een detail.
Bart
bart
12 jaar geleden
 
0 +1 -0 -1
Voorbeeld 18: Statement uitvoeren met gegevensarray als parameter

ik heb een kleine aanpassing van de querie gedaan..


IF NOT EXISTS ( SELECT email FROM tabel WHERE email = :email)

INSERT INTO tabel (naam, leeftijd, email)
VALUES (:naam, :leeftijd, :email)

maar krijg hierop een error

Foutmelding: SQLSTATE[HY000]: General error: 10038 Attempt to initiate a new SQL Server operation with results pending. [10038] (severity 7) [(null)]

hoe kan ik men resultset vrij laten?

voor de rest een goede tutorial, nu kan ik deftig sqlinjection tegen gaan.
Thx

bart
Jelmer -
Jelmer -
12 jaar geleden
 
0 +1 -0 -1
PDOStatement::closeCursor geeft je statement weer vrij voor gebruik.
Bart
bart
12 jaar geleden
 
0 +1 -0 -1
ga ik deze week nog proberen..

thx 4 reply
Bart
bart
11 jaar geleden
 
0 +1 -0 -1
Neen, closeCursor is niet de magishe oplossing..

al iemand geprobeerd?

inserts met IF EXISTS ()
en dit nog een met arrays als variables.

(meerdere keren IF exists())

thx
Bart
bart
11 jaar geleden
 
0 +1 -0 -1
PDOStatement::errorInfo(): Array ( [0] => HY000 [1] => 10038 [2] => Attempt to initiate a new SQL Server operation with results pending. [10038] (severity 7) [(null)] [3] => -1 [4] => 7 )
Jessec
jessec
11 jaar geleden
 
0 +1 -0 -1
Hi,

Dit is nog een leuke variant met BindValue.

$hostname = 'localhost';
$username = '';
$password = '';
$dbname = 'test';

try {
$dbh = new PDO("mysql:host=$hostname;dbname=$dbname", $username, $password);
/*** echo a message saying we have connected ***/
/*** set the error reporting attribute ***/
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
/*** some variables ***/
$data = array('username'=>'name', 'password'=>'pass', 'status'=>'on hold');

$keys = implode(", ", array_keys($data));
$keyparam = ':'.implode(", :", array_keys($data));
$values = implode(", ", array_values($data));
$table = 'users';

$sql = "INSERT INTO $table ($keys) VALUES ($keyparam)";
$stmt = $dbh->prepare($sql);
foreach($data as $k => $v){ $stmt->BindValue(':'.$k ,$v); }
$stmt->execute();

$stmt = $dbh->prepare("SELECT * FROM $table");
$stmt->execute();
$result = $stmt->fetchAll();
foreach($result as $row)
{
foreach(array_keys($data) as $item){
echo ' :: '.$row[$item].' :: ';
}
echo '<br />';
}
/*** close the database connection ***/
$dbh = null;
}
catch(PDOException $e)
{
echo $e->getMessage();
}


Bedankt voor de tutorial.
Unthinking majority
unthinking majority
5 jaar geleden
 
0 +1 -0 -1
Onwijs erg bedankt voor deze tutorial.
Nog wel een vraagje of het bij PDO:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
INSERT INTO tabel (naam)
?>

Of:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
INSERT INTO tabel (`naam`)
?>

is of gewoon hetzelfde.
Wouter Van Marrum
Wouter Van Marrum
5 jaar geleden
 
@arnold, je kunt gewoon dit doen :
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
INSERT INTO tabel (naan)
?>
Wouter J
Wouter J
5 jaar geleden
 
0 +1 -0 -1
Merk op dat PDO slechts een nieuwe manier van communiceren tussen PHP en de database is. De queries zijn onderdeel van de databases en is dus niet veranderd.
PHP hulp
PHP hulp
0 seconden vanaf nu
 

Gesponsorde koppelingen
Thomas van den Heuvel
Thomas van den Heuvel
4 jaar geleden
 
0 +1 -0 -1
Vergeet ook vooral niet om een character encoding in te stellen bij het maken van een verbinding. Als je dit vergeet kan dit voor allerlei onaagename encoderingsproblemen zorgen die pas naar boven komen als je je connectie-parameters hebt gerepareerd.

Vanaf PHP 5.3.6 kun je deze meegeven aan de connectie-string (DSN) via de parameter "charset".

Als je een oudere versie hebt kun je de optie PDO::MYSQL_ATTR_INIT_COMMAND gebruiken met bijvoorbeeld als waarde (voor MySQL) SET NAMES utf8.

De voornaamste gripes die ik heb in het gebruik van PDO (icm een MySQL db, weet niet hoe het met de rest zit) zijn:
- typehints lijken compleet genegeerd te worden, tenzij je parameters zelf al van het goede type zijn
- het debuggen van queries is een ramp, dit heb ik uiteindelijk maar gedaan via een (MySQL) log

En ja, als je dan toch alleen van MySQL gebruik maakt: gebruikt mysqli :).

Om te reageren heb je een account nodig en je moet ingelogd zijn.

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.