PHP Data Objects Wez Furlong <wez@omniti.com>
About the author <ul><li>PHP Core Developer since 2001 </li></ul><ul><li>Author of the Streams layer </li></ul><ul><li>“Ki...
Coming up… <ul><li>Problems with PHP DB access </li></ul><ul><li>PDO Solution </li></ul><ul><li>Features / Drivers </li></...
The Problem <ul><li>No consistency of API between DB extensions </li></ul><ul><li>Sometimes no self-consistency within a g...
The PDO Solution <ul><li>Move PHP specific stuff into one extension </li></ul><ul><li>Database specific stuff (only) in th...
Features <ul><li>Performance </li></ul><ul><li>Native C code beats a scripted solution </li></ul><ul><li>Takes advantage o...
Features <ul><li>Power </li></ul><ul><li>Gives you common DB features as a base </li></ul><ul><li>Still be able to access ...
What can it do? <ul><li>Prepare/execute, bound parameters </li></ul><ul><li>Transactions </li></ul><ul><li>LOBS </li></ul>...
Available Drivers <ul><li>Pretty much all of them: </li></ul><ul><li>MySQL, PostgreSQL </li></ul><ul><li>ODBC, DB2, OCI </...
Installing <ul><li>Ships with PHP 5.1 </li></ul><ul><li>Available for PHP 5.0.x via PECL </li></ul><ul><li>DLLs downloadab...
Building w/ PHP 5.0 <ul><li>./configure    --with-zlib    --prefix=/usr/local/php5 </li></ul><ul><li>pear upgrade pear </l...
Building w/ PHP 5.0 <ul><li>Select the driver(s) you need </li></ul><ul><li>pear install PDO_XXX </li></ul><ul><li>extensi...
Installing on Win32 <ul><li>Grab the DLLs from the snaps site http://snaps.php.net/win32/PECL_5_0/ </li></ul><ul><li>You n...
Switching it on <ul><li>Need to enable PDO in your php.ini </li></ul><ul><li>MUST load PDO first </li></ul><ul><li>Unix: <...
Connecting via PDO <ul><li>try { </li></ul><ul><li>$dbh = new PDO($dsn, $user, </li></ul><ul><li>$password, $options); </l...
DSNs <ul><li>In general </li></ul><ul><ul><li>drivername:<driver-specific-stuff> </li></ul></ul>
DSNs <ul><li>mysql:host=name;dbname=dbname </li></ul><ul><li>pgsql:native_pgsql_connection_string </li></ul><ul><li>odbc:o...
DSNs <ul><li>sqlite:/path/to/db/file </li></ul><ul><li>sqlite::memory: </li></ul><ul><li>sqlite2:/path/to/sqlite2/file </l...
DSN Aliasing <ul><li>uri:uri </li></ul><ul><ul><li>Specify location of a file containing actual DSN on the first line </li...
DSN Aliasing <ul><li>pdo.dsn.name=sqlite:/path/to/name.db </li></ul><ul><li>$dbh = new PDO(&quot;name&quot;); </li></ul><u...
Connection Management <ul><li>try { </li></ul><ul><li>$dbh = new PDO($dsn, $user, $pw); </li></ul><ul><li>// use the datab...
Persistent PDO <ul><li>Connection stays alive between requests </li></ul><ul><li>$dbh = new PDO($dsn, $user, $pass, </li><...
Persistent PDO <ul><li>Can specify your own cache key </li></ul><ul><li>$dbh = new PDO($dsn, $user, $pass, </li></ul><ul><...
Persistent PDO <ul><li>The ODBC driver runs with connection pooling enabled by default </li></ul><ul><li>“ better” than PH...
Let’s get data <ul><li>$dbh = new PDO($dsn); </li></ul><ul><li>$stmt = $dbh->prepare( </li></ul><ul><li>&quot;SELECT * FRO...
Forward-only cursors <ul><li>Also known as &quot;unbuffered&quot; queries in mysql parlance </li></ul><ul><li>They are the...
Forward-only cursors <ul><li>Other queries are likely to block </li></ul><ul><li>You must fetch all remaining data before ...
Buffered Queries <ul><li>$dbh = new PDO($dsn); </li></ul><ul><li>$stmt = $dbh->query( </li></ul><ul><li>&quot;SELECT * FRO...
Data typing <ul><li>Very loose </li></ul><ul><li>uses strings for data </li></ul><ul><li>Gives you more control over data ...
Fetch modes <ul><li>$stmt->fetch(PDO_FETCH_BOTH) </li></ul><ul><ul><li>Array with numeric and string keys </li></ul></ul><...
Fetch modes <ul><li>PDO_FETCH_OBJ </li></ul><ul><ul><li>stdClass object </li></ul></ul><ul><ul><li>$obj->name == ‘name’ co...
Fetch modes <ul><li>PDO_FETCH_COLUMN </li></ul><ul><ul><li>Fetches only a particular column </li></ul></ul><ul><li>PDO_FET...
Iterators <ul><li>$dbh = new PDO($dsn); </li></ul><ul><li>$stmt = $dbh->query( </li></ul><ul><li>&quot;SELECT name FROM FO...
Changing data <ul><li>$deleted = $dbh->exec( </li></ul><ul><li>&quot;DELETE FROM FOO WHERE 1&quot;); </li></ul><ul><li>$ch...
Autonumber/sequences <ul><li>$dbh->exec( </li></ul><ul><li>&quot;insert into foo values (...)&quot;); </li></ul><ul><li>ec...
Smarter queries <ul><li>Quoting is annoying, but essential </li></ul><ul><li>PDO offers a better way </li></ul><ul><li>$st...
Smarter queries <ul><li>Quoting is annoying, but essential </li></ul><ul><li>PDO offers a better way </li></ul><ul><li>$st...
$db->quote() <ul><li>If you still need to quote things “by-hand” </li></ul><ul><li>Currently a no-op for the ODBC driver <...
Stored Procedures <ul><li>$stmt = $dbh->prepare( </li></ul><ul><li>&quot;CALL sp_set_string(?)&quot;); </li></ul><ul><li>$...
OUT parameters <ul><li>$stmt = $dbh->prepare( </li></ul><ul><li>&quot;CALL sp_get_string(?)&quot;); </li></ul><ul><li>$stm...
IN/OUT parameters <ul><li>$stmt = $dbh->prepare( </li></ul><ul><li>&quot;call @sp_inout(?)&quot;); </li></ul><ul><li>$val ...
Binding columns for output <ul><li>$stmt = $dbh->prepare( </li></ul><ul><li>&quot;SELECT extension, name from CREDITS&quot...
Portability Aids <ul><li>PDO aims to make it easier to write db independent apps </li></ul><ul><li>Number of hacks^Wtweaks...
Oracle style NULLs <ul><li>Oracle translates empty strings into NULLs </li></ul><ul><li>$dbh->setAttribute(PDO_ATTR_ORACLE...
Case folding <ul><li>The ANSI SQL standard says that column names are returned in upper case </li></ul><ul><li>High end da...
Error Handling <ul><li>PDO offers 3 different error modes </li></ul><ul><li>$dbh->setAttribute(PDO_ATTR_ERRMODE, $mode); <...
PDO_ERRMODE_SILENT <ul><li>if (!$dbh->query($sql)) { </li></ul><ul><li>echo $dbh->errorCode() . &quot;<br>&quot;; </li></u...
PDO_ERRMODE_WARNING <ul><li>Same as PDO_ERRMODE_SILENT </li></ul><ul><li>But, raises an E_WARNING as errors are detected <...
PDO_ERRMODE_EXCEPTION <ul><li>try { </li></ul><ul><li>$dbh->exec($sql); </li></ul><ul><li>} catch (PDOException $e) { </li...
Transactions <ul><li>$dbh->beginTransaction(); </li></ul><ul><li>try { </li></ul><ul><li>$dbh->query(&quot;UPDATE ...&quot...
LOBs via Streams <ul><li>Large objects are usually 4kb or more in size </li></ul><ul><li>Advantageous to avoid fetching th...
Fetching an image <ul><li>$db = new PDO($dsn); </li></ul><ul><li>$stmt = $db->prepare( </li></ul><ul><li>“ select contentt...
Inserting an image <ul><li>$db = new PDO($dsn); </li></ul><ul><li>$stmt = $db->prepare( </li></ul><ul><li>“ insert into im...
Scrollable Cursors <ul><li>Allow random access to a rowset </li></ul><ul><li>Higher resource usage than forward-only curso...
Positioned updates <ul><li>An open (scrollable) cursor can be used to target a row for another query </li></ul><ul><li>Nam...
Multi-rowset queries <ul><li>$stmt = $dbh->query( </li></ul><ul><li>&quot;call sp_multi_results()&quot;); </li></ul><ul><l...
Questions?
Resources <ul><li>The PHP Manual: http://php.net/pdo </li></ul><ul><li>Publications </li></ul><ul><ul><li>www-128.ibm.com/...
Upcoming SlideShare
Loading in...5
×

Here are the slides from my PDO talk (powerpoint)

1,272

Published on

0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,272
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
29
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Here are the slides from my PDO talk (powerpoint)

  1. 1. PHP Data Objects Wez Furlong <wez@omniti.com>
  2. 2. About the author <ul><li>PHP Core Developer since 2001 </li></ul><ul><li>Author of the Streams layer </li></ul><ul><li>“King” of PECL </li></ul><ul><li>Author of most of PDO and its drivers </li></ul><ul><li>Day-job is developing the Fastest MTA on Earth </li></ul>
  3. 3. Coming up… <ul><li>Problems with PHP DB access </li></ul><ul><li>PDO Solution </li></ul><ul><li>Features / Drivers </li></ul><ul><li>Installation </li></ul><ul><li>Getting Started </li></ul><ul><li>Features </li></ul>
  4. 4. The Problem <ul><li>No consistency of API between DB extensions </li></ul><ul><li>Sometimes no self-consistency within a given extension </li></ul><ul><li>Duplicated code (but not) </li></ul><ul><li>High maintenance </li></ul>
  5. 5. The PDO Solution <ul><li>Move PHP specific stuff into one extension </li></ul><ul><li>Database specific stuff (only) in their own extensions </li></ul><ul><li>Data access abstraction, not database abstraction </li></ul>
  6. 6. Features <ul><li>Performance </li></ul><ul><li>Native C code beats a scripted solution </li></ul><ul><li>Takes advantage of latest PHP 5 internals </li></ul>
  7. 7. Features <ul><li>Power </li></ul><ul><li>Gives you common DB features as a base </li></ul><ul><li>Still be able to access specialist functions </li></ul>
  8. 8. What can it do? <ul><li>Prepare/execute, bound parameters </li></ul><ul><li>Transactions </li></ul><ul><li>LOBS </li></ul><ul><li>Scrollable Cursors </li></ul><ul><li>SQLSTATE error codes, flexible error handling </li></ul><ul><li>Portability attributes </li></ul>
  9. 9. Available Drivers <ul><li>Pretty much all of them: </li></ul><ul><li>MySQL, PostgreSQL </li></ul><ul><li>ODBC, DB2, OCI </li></ul><ul><li>SQLite (2 and 3) </li></ul><ul><li>Sybase/FreeTDS/MSSQL </li></ul><ul><li>Firebird (needs love) </li></ul>
  10. 10. Installing <ul><li>Ships with PHP 5.1 </li></ul><ul><li>Available for PHP 5.0.x via PECL </li></ul><ul><li>DLLs downloadable for both on Windows via http://snaps.php.net </li></ul>
  11. 11. Building w/ PHP 5.0 <ul><li>./configure --with-zlib --prefix=/usr/local/php5 </li></ul><ul><li>pear upgrade pear </li></ul><ul><li>pear install PDO </li></ul><ul><li>extension=pdo.so in your php.ini </li></ul>
  12. 12. Building w/ PHP 5.0 <ul><li>Select the driver(s) you need </li></ul><ul><li>pear install PDO_XXX </li></ul><ul><li>extension=pdo_xxx.so in your php.ini </li></ul>
  13. 13. Installing on Win32 <ul><li>Grab the DLLs from the snaps site http://snaps.php.net/win32/PECL_5_0/ </li></ul><ul><li>You need: </li></ul><ul><ul><li>php_pdo.dll </li></ul></ul><ul><ul><li>php_pdo_XXX.dll </li></ul></ul><ul><li>Put them in C:php5ext </li></ul>
  14. 14. Switching it on <ul><li>Need to enable PDO in your php.ini </li></ul><ul><li>MUST load PDO first </li></ul><ul><li>Unix: </li></ul><ul><ul><li>extension=pdo.so </li></ul></ul><ul><ul><li>extension=pdo_XXX.so </li></ul></ul><ul><li>Windows: </li></ul><ul><ul><li>extension=php_pdo.dll </li></ul></ul><ul><ul><li>extension=php_pdo_XXX.dll </li></ul></ul>
  15. 15. Connecting via PDO <ul><li>try { </li></ul><ul><li>$dbh = new PDO($dsn, $user, </li></ul><ul><li>$password, $options); </li></ul><ul><li>} catch (PDOException $e) { </li></ul><ul><li>   echo ”Failed to connect:” </li></ul><ul><li>. $e->getMessage(); </li></ul><ul><li>} </li></ul>
  16. 16. DSNs <ul><li>In general </li></ul><ul><ul><li>drivername:<driver-specific-stuff> </li></ul></ul>
  17. 17. DSNs <ul><li>mysql:host=name;dbname=dbname </li></ul><ul><li>pgsql:native_pgsql_connection_string </li></ul><ul><li>odbc:odbc_dsn </li></ul><ul><li>oci:dbname=dbname;charset=charset </li></ul>
  18. 18. DSNs <ul><li>sqlite:/path/to/db/file </li></ul><ul><li>sqlite::memory: </li></ul><ul><li>sqlite2:/path/to/sqlite2/file </li></ul><ul><li>sqlite2::memory: </li></ul>
  19. 19. DSN Aliasing <ul><li>uri:uri </li></ul><ul><ul><li>Specify location of a file containing actual DSN on the first line </li></ul></ul><ul><ul><li>Works with streams interface, so remote URLs can work too </li></ul></ul><ul><li>name (with no colon) </li></ul><ul><ul><li>Maps to pdo.dsn.name in your php.ini </li></ul></ul><ul><ul><li>pdo.dsn.name=sqlite:/path/to/name.db </li></ul></ul>
  20. 20. DSN Aliasing <ul><li>pdo.dsn.name=sqlite:/path/to/name.db </li></ul><ul><li>$dbh = new PDO(&quot;name&quot;); </li></ul><ul><li>Same as: </li></ul><ul><li>$dbh = new PDO(&quot;sqlite:/path/to/name.db&quot;); </li></ul>
  21. 21. Connection Management <ul><li>try { </li></ul><ul><li>$dbh = new PDO($dsn, $user, $pw); </li></ul><ul><li>// use the database here </li></ul><ul><li>// ... </li></ul><ul><li>// done; release the connection </li></ul><ul><li>$dbh = null;  </li></ul><ul><li>} catch (PDOException $e) { </li></ul><ul><li>echo ”connect failed:” </li></ul><ul><li>  . $e->getMessage(); </li></ul><ul><li>} </li></ul>
  22. 22. Persistent PDO <ul><li>Connection stays alive between requests </li></ul><ul><li>$dbh = new PDO($dsn, $user, $pass, </li></ul><ul><li>array( </li></ul><ul><li>PDO_ATTR_PERSISTENT => true </li></ul><ul><li>) </li></ul><ul><li>); </li></ul>
  23. 23. Persistent PDO <ul><li>Can specify your own cache key </li></ul><ul><li>$dbh = new PDO($dsn, $user, $pass, </li></ul><ul><li>array( </li></ul><ul><li>PDO_ATTR_PERSISTENT => “my-key” </li></ul><ul><li>) </li></ul><ul><li>); </li></ul><ul><li>Useful for keeping separate persistent connections </li></ul>
  24. 24. Persistent PDO <ul><li>The ODBC driver runs with connection pooling enabled by default </li></ul><ul><li>“ better” than PHP-level persistence </li></ul><ul><ul><li>Pool is shared at the process level </li></ul></ul><ul><li>Can be forced off by setting </li></ul><ul><ul><li>pdo_odbc.connection_pooling=off </li></ul></ul>
  25. 25. Let’s get data <ul><li>$dbh = new PDO($dsn); </li></ul><ul><li>$stmt = $dbh->prepare( </li></ul><ul><li>&quot;SELECT * FROM FOO&quot;); </li></ul><ul><li>$stmt->execute(); </li></ul><ul><li>while ($row = $stmt->fetch()) { </li></ul><ul><li>print_r($row); </li></ul><ul><li>} </li></ul><ul><li>$stmt = null; </li></ul>
  26. 26. Forward-only cursors <ul><li>Also known as &quot;unbuffered&quot; queries in mysql parlance </li></ul><ul><li>They are the default cursor type </li></ul><ul><li>rowCount() doesn't have meaning </li></ul><ul><li>FAST! </li></ul>
  27. 27. Forward-only cursors <ul><li>Other queries are likely to block </li></ul><ul><li>You must fetch all remaining data before launching another query </li></ul><ul><li>$stmt->closeCursor() </li></ul>
  28. 28. Buffered Queries <ul><li>$dbh = new PDO($dsn); </li></ul><ul><li>$stmt = $dbh->query( </li></ul><ul><li>&quot;SELECT * FROM FOO&quot;); </li></ul><ul><li>$rows = $stmt->fetchAll(); </li></ul><ul><li>$count = count($rows); </li></ul><ul><li>foreach ($rows as $row) { </li></ul><ul><li>print_r($row); </li></ul><ul><li>} </li></ul><ul><li>$stmt = null; </li></ul>
  29. 29. Data typing <ul><li>Very loose </li></ul><ul><li>uses strings for data </li></ul><ul><li>Gives you more control over data conversion </li></ul><ul><li>Supports integers where 1:1 mapping exists </li></ul><ul><li>Is float agnostic </li></ul><ul><ul><li>PDO is precise </li></ul></ul>
  30. 30. Fetch modes <ul><li>$stmt->fetch(PDO_FETCH_BOTH) </li></ul><ul><ul><li>Array with numeric and string keys </li></ul></ul><ul><ul><li>default option </li></ul></ul><ul><li>PDO_FETCH_NUM </li></ul><ul><ul><li>Numeric only </li></ul></ul><ul><li>PDO_FETCH_ASSOC </li></ul><ul><ul><li>String only </li></ul></ul>
  31. 31. Fetch modes <ul><li>PDO_FETCH_OBJ </li></ul><ul><ul><li>stdClass object </li></ul></ul><ul><ul><li>$obj->name == ‘name’ column </li></ul></ul><ul><li>PDO_FETCH_CLASS </li></ul><ul><ul><li>You choose the class </li></ul></ul><ul><li>PDO_FETCH_INTO </li></ul><ul><ul><li>You provide the object </li></ul></ul>
  32. 32. Fetch modes <ul><li>PDO_FETCH_COLUMN </li></ul><ul><ul><li>Fetches only a particular column </li></ul></ul><ul><li>PDO_FETCH_BOUND </li></ul><ul><ul><li>Only fetches into bound variables </li></ul></ul><ul><li>PDO_FETCH_FUNC </li></ul><ul><ul><li>Returns the result of a callback </li></ul></ul><ul><li>and more… </li></ul>
  33. 33. Iterators <ul><li>$dbh = new PDO($dsn); </li></ul><ul><li>$stmt = $dbh->query( </li></ul><ul><li>&quot;SELECT name FROM FOO&quot;, </li></ul><ul><li>PDO_FETCH_COLUMN, 0); </li></ul><ul><li>foreach ($stmt as $name) { </li></ul><ul><li>echo &quot;Name: $name &quot;; </li></ul><ul><li>} </li></ul><ul><li>$stmt = null; </li></ul>
  34. 34. Changing data <ul><li>$deleted = $dbh->exec( </li></ul><ul><li>&quot;DELETE FROM FOO WHERE 1&quot;); </li></ul><ul><li>$changes = $dbh->exec( </li></ul><ul><li>&quot;UPDATE FOO SET active=1 &quot; </li></ul><ul><li>. &quot;WHERE NAME LIKE '%joe%'&quot;); </li></ul>
  35. 35. Autonumber/sequences <ul><li>$dbh->exec( </li></ul><ul><li>&quot;insert into foo values (...)&quot;); </li></ul><ul><li>echo $dbh->lastInsertId(); </li></ul><ul><li>$dbh->exec( </li></ul><ul><li>&quot;insert into foo values (...)&quot;); </li></ul><ul><li>echo $dbh->lastInsertId(“seqname”); </li></ul><ul><li>It’s up to you to call it appropriately </li></ul>
  36. 36. Smarter queries <ul><li>Quoting is annoying, but essential </li></ul><ul><li>PDO offers a better way </li></ul><ul><li>$stmt->prepare(“INSERT INTO CREDITS ” </li></ul><ul><li>.“(extension, name) ” </li></ul><ul><li>.“VALUES (:extension, :name)”); </li></ul><ul><li>$stmt->execute(array( </li></ul><ul><li>'extension' => 'xdebug', </li></ul><ul><li>'name' => 'Derick Rethans' </li></ul><ul><li>)); </li></ul>
  37. 37. Smarter queries <ul><li>Quoting is annoying, but essential </li></ul><ul><li>PDO offers a better way </li></ul><ul><li>$stmt->prepare(“INSERT INTO CREDITS ” </li></ul><ul><li>.“(extension, name) ” </li></ul><ul><li>.“VALUES (?, ?)”); </li></ul><ul><li>$stmt->execute(array( </li></ul><ul><li>'xdebug', </li></ul><ul><li>'Derick Rethans' </li></ul><ul><li>)); </li></ul>
  38. 38. $db->quote() <ul><li>If you still need to quote things “by-hand” </li></ul><ul><li>Currently a no-op for the ODBC driver </li></ul>
  39. 39. Stored Procedures <ul><li>$stmt = $dbh->prepare( </li></ul><ul><li>&quot;CALL sp_set_string(?)&quot;); </li></ul><ul><li>$stmt->bindParam(1, $str); </li></ul><ul><li>$str = ‘foo’; </li></ul><ul><li>$stmt->execute(); </li></ul>
  40. 40. OUT parameters <ul><li>$stmt = $dbh->prepare( </li></ul><ul><li>&quot;CALL sp_get_string(?)&quot;); </li></ul><ul><li>$stmt->bindParam(1, $ret, </li></ul><ul><li>PDO_PARAM_STR, 4000); </li></ul><ul><li>if ($stmt->execute()) { </li></ul><ul><li>echo &quot;Got $ret &quot;; </li></ul><ul><li>} </li></ul>
  41. 41. IN/OUT parameters <ul><li>$stmt = $dbh->prepare( </li></ul><ul><li>&quot;call @sp_inout(?)&quot;); </li></ul><ul><li>$val = &quot;My Input Data&quot;; </li></ul><ul><li>$stmt->bindParam(1, $val, </li></ul><ul><li>PDO_PARAM_STR| </li></ul><ul><li>PDO_PARAM_INPUT_OUTPUT, </li></ul><ul><li>4000); </li></ul><ul><li>if ($stmt->execute()) { </li></ul><ul><li>echo &quot;Got $val &quot;; </li></ul><ul><li>} </li></ul>
  42. 42. Binding columns for output <ul><li>$stmt = $dbh->prepare( </li></ul><ul><li>&quot;SELECT extension, name from CREDITS&quot;); </li></ul><ul><li>if ($stmt->execute()) { </li></ul><ul><li>$stmt->bindColumn('extension', $extension); </li></ul><ul><li>$stmt->bindColumn('name', $name); </li></ul><ul><li>while ($stmt->fetch(PDO_FETCH_BOUND)) { </li></ul><ul><li>echo &quot;Extension: $extension &quot;; </li></ul><ul><li>echo &quot;Author: $name &quot;; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  43. 43. Portability Aids <ul><li>PDO aims to make it easier to write db independent apps </li></ul><ul><li>Number of hacks^Wtweaks for this purpose </li></ul>
  44. 44. Oracle style NULLs <ul><li>Oracle translates empty strings into NULLs </li></ul><ul><li>$dbh->setAttribute(PDO_ATTR_ORACLE_NULLS, true); </li></ul><ul><li>Translates empty strings into NULLs when fetching data </li></ul><ul><li>But won’t change them on insert </li></ul>
  45. 45. Case folding <ul><li>The ANSI SQL standard says that column names are returned in upper case </li></ul><ul><li>High end databases (eg: Oracle and DB2) respect this </li></ul><ul><li>Most others don’t </li></ul><ul><li>$dbh->setAttribute( </li></ul><ul><li>PDO_ATTR_CASE,PDO_CASE_UPPER); </li></ul>
  46. 46. Error Handling <ul><li>PDO offers 3 different error modes </li></ul><ul><li>$dbh->setAttribute(PDO_ATTR_ERRMODE, $mode); </li></ul><ul><ul><li>PDO_ERRMODE_SILENT </li></ul></ul><ul><ul><li>PDO_ERRMODE_WARNING </li></ul></ul><ul><ul><li>PDO_ERRMODE_EXCEPTION </li></ul></ul><ul><li>Attempts to map native codes to SQLSTATE standard codes </li></ul><ul><li>But still offers native info too </li></ul>
  47. 47. PDO_ERRMODE_SILENT <ul><li>if (!$dbh->query($sql)) { </li></ul><ul><li>echo $dbh->errorCode() . &quot;<br>&quot;; </li></ul><ul><li>$info = $dbh->errorInfo(); </li></ul><ul><li>// $info[0] == $dbh->errorCode() </li></ul><ul><li>// SQLSTATE error code </li></ul><ul><li>// $info[1] is the driver specific </li></ul><ul><li>// error code </li></ul><ul><li>// $info[2] is the driver specific </li></ul><ul><li>// error string </li></ul><ul><li>} </li></ul>
  48. 48. PDO_ERRMODE_WARNING <ul><li>Same as PDO_ERRMODE_SILENT </li></ul><ul><li>But, raises an E_WARNING as errors are detected </li></ul><ul><li>You can selectively suppress the warnings with @ operator </li></ul>
  49. 49. PDO_ERRMODE_EXCEPTION <ul><li>try { </li></ul><ul><li>$dbh->exec($sql); </li></ul><ul><li>} catch (PDOException $e) { </li></ul><ul><li>// display warning message print </li></ul><ul><li>$e->getMessage(); </li></ul><ul><li>$info = $e->errorInfo; </li></ul><ul><li>// $info[0] == $e->code; </li></ul><ul><li>// SQLSTATE error code </li></ul><ul><li>// $info[1] is the driver specific error code </li></ul><ul><li>// $info[2] is the driver specific error string </li></ul><ul><li>} </li></ul>
  50. 50. Transactions <ul><li>$dbh->beginTransaction(); </li></ul><ul><li>try { </li></ul><ul><li>$dbh->query(&quot;UPDATE ...&quot;); </li></ul><ul><li>$dbh->query(&quot;UPDATE ...&quot;); </li></ul><ul><li>$dbh->commit(); </li></ul><ul><li>} catch (Exception $e) { </li></ul><ul><li>$dbh->rollBack(); </li></ul><ul><li>} </li></ul>
  51. 51. LOBs via Streams <ul><li>Large objects are usually 4kb or more in size </li></ul><ul><li>Advantageous to avoid fetching them until you really need to </li></ul><ul><li>Mature RDBMS offer LOB APIs for this </li></ul><ul><li>PDO exposes LOBS as Streams </li></ul>
  52. 52. Fetching an image <ul><li>$db = new PDO($dsn); </li></ul><ul><li>$stmt = $db->prepare( </li></ul><ul><li>“ select contenttype, imagedata” </li></ul><ul><li>.“ from images where id=?”); </li></ul><ul><li>$stmt->execute(array($_GET['id'])); </li></ul><ul><li>list($type, $lob) = $stmt->fetch(); </li></ul><ul><li>header(&quot;Content-Type: $type&quot;); </li></ul><ul><li>fpassthru($lob); </li></ul>
  53. 53. Inserting an image <ul><li>$db = new PDO($dsn); </li></ul><ul><li>$stmt = $db->prepare( </li></ul><ul><li>“ insert into images ” </li></ul><ul><li>.“(id, contenttype, imagedata) ” </li></ul><ul><li>.“values (?, ?, ?)”); </li></ul><ul><li>$id = get_new_id(); </li></ul><ul><li>$fp = fopen($_FILES['file']['tmp_name'], </li></ul><ul><li>'rb'); </li></ul><ul><li>$stmt->bindParam(1, $id); </li></ul><ul><li>$stmt->bindParam(2,$_FILES['file']['type']); </li></ul><ul><li>$stmt->bindParam(3, $fp, PDO_PARAM_LOB); </li></ul><ul><li>$stmt->execute(); </li></ul>
  54. 54. Scrollable Cursors <ul><li>Allow random access to a rowset </li></ul><ul><li>Higher resource usage than forward-only cursors </li></ul><ul><li>Can be used to emulate limit, offset style paged queries </li></ul><ul><li>Can be used for positioned updates (more useful for CLI/GUI apps) </li></ul>
  55. 55. Positioned updates <ul><li>An open (scrollable) cursor can be used to target a row for another query </li></ul><ul><li>Name your cursor by setting PDO_ATTR_CURSOR_NAME during prepare() </li></ul><ul><li>UPDATE foo set bar = ? WHERE CURRENT OF cursor_name </li></ul>
  56. 56. Multi-rowset queries <ul><li>$stmt = $dbh->query( </li></ul><ul><li>&quot;call sp_multi_results()&quot;); </li></ul><ul><li>do { </li></ul><ul><li>while($row = $stmt->fetch()) { </li></ul><ul><li>print_r($row); </li></ul><ul><li>} </li></ul><ul><li>} while ($stmt->nextRowset()); </li></ul>
  57. 57. Questions?
  58. 58. Resources <ul><li>The PHP Manual: http://php.net/pdo </li></ul><ul><li>Publications </li></ul><ul><ul><li>www-128.ibm.com/developerworks/db2/library/techarticle/ dm-0505furlong/ </li></ul></ul><ul><ul><li>www.oracle.com/technology/pub/articles/php_experts/ otn_pdo_oracle5.html </li></ul></ul><ul><li>My blog: http://netevil.org </li></ul><ul><li>Bugs: http://bugs.php.net </li></ul>
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×