PHP Data Objects

    Wez Furlong
    Lead Architect
 <wez@omniti.com>
we're hiring: 
                  http://omniti.com/people/jobs



              About the author
•   PHP Core Developer si...
we're hiring: 
                  http://omniti.com/people/jobs



                Coming up…
•   Problems with PHP DB acce...
we're hiring: 
                 http://omniti.com/people/jobs



               The Problem
• No consistency of API betwee...
we're hiring: 
                 http://omniti.com/people/jobs



            The PDO Solution
• Move PHP specific stuff in...
we're hiring: 
                 http://omniti.com/people/jobs



                   Features
Performance
• Native C code b...
we're hiring: 
                  http://omniti.com/people/jobs



                    Features
Power
• Gives you common DB...
we're hiring: 
                   http://omniti.com/people/jobs



               What can it do?
•   Prepare/execute, bou...
we're hiring: 
                   http://omniti.com/people/jobs



              Available Drivers
•   Pretty much all of ...
we're hiring: 
                http://omniti.com/people/jobs



                 Installing
• Ships with PHP 5.1
• Availab...
we're hiring: 
              http://omniti.com/people/jobs



        Building w/ PHP 5.0
./configure 
       ‐‐with‐zlib ...
we're hiring: 
              http://omniti.com/people/jobs



         Building w/ PHP 5.0
• Select the driver(s) you need...
we're hiring: 
                 http://omniti.com/people/jobs



           Installing on Win32
• Grab the DLLs from the s...
we're hiring: 
                http://omniti.com/people/jobs



             Switching it on
• Need to enable PDO in your ...
we're hiring: 
            http://omniti.com/people/jobs



       Connecting via PDO
try {
  $dbh = new PDO($dsn, $user,
...
we're hiring: 
                  http://omniti.com/people/jobs



                         DSNs
• In general
  drivername:...
we're hiring: 
                http://omniti.com/people/jobs



                       DSNs
• mysql:host=name;dbname=dbnam...
we're hiring: 
                  http://omniti.com/people/jobs



                         DSNs
• sqlite:/path/to/db/file
...
we're hiring: 
                    http://omniti.com/people/jobs



                  DSN Aliasing
• uri:uri
   – Specify ...
we're hiring: 
                 http://omniti.com/people/jobs



               DSN Aliasing
• pdo.dsn.name=sqlite:/path/t...
we're hiring: 
              http://omniti.com/people/jobs



     Connection Management
try {
  $dbh = new PDO($dsn, $use...
we're hiring: 
                http://omniti.com/people/jobs



             Persistent PDO
• Connection stays alive betwe...
we're hiring: 
                   http://omniti.com/people/jobs



               Persistent PDO
• Can specify your own ca...
we're hiring: 
                   http://omniti.com/people/jobs



               Persistent PDO
• The ODBC driver runs wi...
we're hiring: 
              http://omniti.com/people/jobs



            Let’s get data
$dbh = new PDO($dsn);
$stmt = $db...
we're hiring: 
                http://omniti.com/people/jobs



         Forward‐only cursors
• Also known as quot;unbuffe...
we're hiring: 
                 http://omniti.com/people/jobs



         Forward‐only cursors
• Other queries are likely ...
we're hiring: 
              http://omniti.com/people/jobs



          Buffered Queries
$dbh = new PDO($dsn);
$stmt = $db...
we're hiring: 
                       http://omniti.com/people/jobs



                   Data typing
•   Very loose
•   u...
we're hiring: 
                   http://omniti.com/people/jobs



                  Fetch modes
• $stmt‐>fetch(PDO::FETCH...
we're hiring: 
                  http://omniti.com/people/jobs



                Fetch modes
• PDO::FETCH_OBJ
  – stdClas...
we're hiring: 
                   http://omniti.com/people/jobs



                 Fetch modes
• PDO::FETCH_COLUMN
  – Fe...
we're hiring: 
               http://omniti.com/people/jobs



                 Iterators
$dbh = new PDO($dsn);
$stmt = $d...
we're hiring: 
            http://omniti.com/people/jobs



          Changing data
$deleted = $dbh‐>exec(
    quot;DELETE...
we're hiring: 
                     http://omniti.com/people/jobs



         Autonumber/sequences
$dbh‐>exec(
     quot;i...
we're hiring: 
                      http://omniti.com/people/jobs



                 Smarter queries
• Quoting is annoyi...
we're hiring: 
                      http://omniti.com/people/jobs



                 Smarter queries
• Quoting is annoyi...
we're hiring: 
                 http://omniti.com/people/jobs



               $db‐>quote()
• If you still need to quote ...
we're hiring: 
              http://omniti.com/people/jobs



         Stored Procedures
$stmt = $dbh‐>prepare(
          ...
we're hiring: 
              http://omniti.com/people/jobs



          OUT parameters
$stmt = $dbh‐>prepare(
            ...
we're hiring: 
                 http://omniti.com/people/jobs



          IN/OUT parameters
$stmt = $dbh‐>prepare(
      ...
we're hiring: 
                 http://omniti.com/people/jobs



     Binding columns for output
$stmt = $dbh‐>prepare(
  ...
we're hiring: 
               http://omniti.com/people/jobs



            Portability Aids
• PDO aims to make it easier t...
we're hiring: 
                    http://omniti.com/people/jobs



             Oracle style NULLs
• Oracle translates em...
we're hiring: 
                http://omniti.com/people/jobs



               Case folding
• The ANSI SQL standard says t...
we're hiring: 
                http://omniti.com/people/jobs



             Error Handling
• PDO offers 3 different error...
we're hiring: 
              http://omniti.com/people/jobs



      PDO::ERRMODE_SILENT
if (!$dbh‐>query($sql)) {
   echo ...
we're hiring: 
                 http://omniti.com/people/jobs



     PDO::ERRMODE_WARNING
• Same as PDO::ERRMODE_SILENT
•...
we're hiring: 
                    http://omniti.com/people/jobs



     PDO_ERRMODE_EXCEPTION
try {
   $dbh‐>exec($sql);
...
we're hiring: 
            http://omniti.com/people/jobs



           Transactions
$dbh‐>beginTransaction();
try {
   $db...
we're hiring: 
                 http://omniti.com/people/jobs



            LOBs via Streams
• Large objects are usually ...
we're hiring: 
                 http://omniti.com/people/jobs



           Fetching an image
$db = new PDO($dsn);
$stmt =...
we're hiring: 
                 http://omniti.com/people/jobs



           Inserting an image
$db = new PDO($dsn);
$stmt ...
we're hiring: 
                 http://omniti.com/people/jobs



            Scrollable Cursors
• Allow random access to a...
we're hiring: 
                http://omniti.com/people/jobs



          Positioned updates
• An open (scrollable) cursor...
we're hiring: 
             http://omniti.com/people/jobs



       Multi‐rowset queries
$stmt = $dbh‐>query(
      quot;c...
we're hiring: 
                           http://omniti.com/people/jobs



                         Questions?
• These sli...
Upcoming SlideShare
Loading in...5
×

Os Furlong

1,268

Published on

Published in: Business, Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

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

No notes for slide

Transcript of "Os Furlong"

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

×