php data objects
DESCRIPTION
PHP Data Objects. Wez Furlong . 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. Coming up…. Problems with PHP DB access PDO Solution - PowerPoint PPT PresentationTRANSCRIPT
![Page 2: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/2.jpg)
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
![Page 3: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/3.jpg)
Coming up…
• Problems with PHP DB access• PDO Solution• Features / Drivers• Installation• Getting Started• Features
![Page 4: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/4.jpg)
The Problem
• No consistency of API between DB extensions
• Sometimes no self-consistency within a given extension
• Duplicated code (but not)• High maintenance
![Page 5: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/5.jpg)
The PDO Solution
• Move PHP specific stuff into one extension
• Database specific stuff (only) in their own extensions
• Data access abstraction, not database abstraction
![Page 6: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/6.jpg)
Features
Performance• Native C code beats a scripted
solution• Takes advantage of latest PHP 5
internals
![Page 7: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/7.jpg)
Features
Power• Gives you common DB features as a
base• Still be able to access specialist
functions
![Page 8: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/8.jpg)
What can it do?
• Prepare/execute, bound parameters• Transactions• LOBS• Scrollable Cursors• SQLSTATE error codes, flexible error
handling• Portability attributes
![Page 9: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/9.jpg)
Available Drivers
• Pretty much all of them:• MySQL, PostgreSQL• ODBC, DB2, OCI• SQLite (2 and 3)• Sybase/FreeTDS/MSSQL• Firebird (needs love)
![Page 10: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/10.jpg)
Installing
• Ships with PHP 5.1• Available for PHP 5.0.x via PECL• DLLs downloadable for both on
Windows via http://snaps.php.net
![Page 11: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/11.jpg)
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
![Page 12: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/12.jpg)
Building w/ PHP 5.0
• Select the driver(s) you need• pear install PDO_XXX• extension=pdo_xxx.so in your
php.ini
![Page 13: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/13.jpg)
Installing on Win32
• Grab the DLLs from the snaps site http://snaps.php.net/win32/PECL_5_0/
• You need:– php_pdo.dll– php_pdo_XXX.dll
• Put them in C:\php5\ext
![Page 14: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/14.jpg)
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
![Page 15: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/15.jpg)
Connecting via PDO
try {
$dbh = new PDO($dsn, $user,
$password, $options);
} catch (PDOException $e) {
echo ”Failed to connect:”
. $e->getMessage();
}
![Page 16: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/16.jpg)
DSNs
• In generaldrivername:<driver-specific-stuff>
![Page 17: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/17.jpg)
DSNs
• mysql:host=name;dbname=dbname• pgsql:native_pgsql_connection_string
• odbc:odbc_dsn• oci:dbname=dbname;charset=chars
et
![Page 18: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/18.jpg)
DSNs
• sqlite:/path/to/db/file• sqlite::memory:
• sqlite2:/path/to/sqlite2/file• sqlite2::memory:
![Page 19: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/19.jpg)
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
![Page 20: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/20.jpg)
DSN Aliasing
• pdo.dsn.name=sqlite:/path/to/name.db
$dbh = new PDO("name");
Same as:
$dbh = new PDO("sqlite:/path/to/name.db");
![Page 21: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/21.jpg)
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();}
![Page 22: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/22.jpg)
Persistent PDO
• Connection stays alive between requests
$dbh = new PDO($dsn, $user, $pass,
array(
PDO_ATTR_PERSISTENT => true
)
);
![Page 23: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/23.jpg)
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
![Page 24: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/24.jpg)
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
![Page 25: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/25.jpg)
Let’s get data
$dbh = new PDO($dsn);$stmt = $dbh->prepare( "SELECT * FROM FOO");$stmt->execute();while ($row = $stmt->fetch()) { print_r($row);}$stmt = null;
![Page 26: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/26.jpg)
Forward-only cursors
• Also known as "unbuffered" queries in mysql parlance
• They are the default cursor type• rowCount() doesn't have meaning• FAST!
![Page 27: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/27.jpg)
Forward-only cursors
• Other queries are likely to block• You must fetch all remaining data
before launching another query• $stmt->closeCursor()
![Page 28: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/28.jpg)
Buffered Queries
$dbh = new PDO($dsn);$stmt = $dbh->query( "SELECT * FROM FOO");$rows = $stmt->fetchAll();$count = count($rows);foreach ($rows as $row) { print_r($row);}$stmt = null;
![Page 29: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/29.jpg)
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
![Page 30: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/30.jpg)
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
![Page 31: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/31.jpg)
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
![Page 32: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/32.jpg)
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…
![Page 33: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/33.jpg)
Iterators
$dbh = new PDO($dsn);
$stmt = $dbh->query(
"SELECT name FROM FOO",
PDO_FETCH_COLUMN, 0);
foreach ($stmt as $name) {
echo "Name: $name\n";
}
$stmt = null;
![Page 34: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/34.jpg)
Changing data
$deleted = $dbh->exec(
"DELETE FROM FOO WHERE 1");
$changes = $dbh->exec(
"UPDATE FOO SET active=1 "
. "WHERE NAME LIKE '%joe%'");
![Page 35: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/35.jpg)
Autonumber/sequences
$dbh->exec( "insert into foo values (...)");echo $dbh->lastInsertId();
$dbh->exec( "insert into foo values (...)");echo $dbh->lastInsertId(“seqname”);
It’s up to you to call it appropriately
![Page 36: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/36.jpg)
Smarter queries
• Quoting is annoying, but essential• PDO offers a better way
$stmt->prepare(“INSERT INTO CREDITS ” .“(extension, name) ” .“VALUES (:extension, :name)”);$stmt->execute(array( 'extension' => 'xdebug', 'name' => 'Derick Rethans'));
![Page 37: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/37.jpg)
Smarter queries
• Quoting is annoying, but essential• PDO offers a better way
$stmt->prepare(“INSERT INTO CREDITS ” .“(extension, name) ” .“VALUES (?, ?)”);$stmt->execute(array( 'xdebug', 'Derick Rethans'));
![Page 38: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/38.jpg)
$db->quote()
• If you still need to quote things “by-hand”
• Currently a no-op for the ODBC driver
![Page 39: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/39.jpg)
Stored Procedures
$stmt = $dbh->prepare(
"CALL sp_set_string(?)");
$stmt->bindParam(1, $str);
$str = ‘foo’;
$stmt->execute();
![Page 40: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/40.jpg)
OUT parameters
$stmt = $dbh->prepare(
"CALL sp_get_string(?)");
$stmt->bindParam(1, $ret,
PDO_PARAM_STR, 4000);
if ($stmt->execute()) {
echo "Got $ret\n";
}
![Page 41: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/41.jpg)
IN/OUT parameters
$stmt = $dbh->prepare(
"call @sp_inout(?)");
$val = "My Input Data";
$stmt->bindParam(1, $val,
PDO_PARAM_STR|
PDO_PARAM_INPUT_OUTPUT,
4000);
if ($stmt->execute()) {
echo "Got $val\n";
}
![Page 42: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/42.jpg)
Binding columns for output
$stmt = $dbh->prepare( "SELECT extension, name from CREDITS");if ($stmt->execute()) { $stmt->bindColumn('extension', $extension); $stmt->bindColumn('name', $name); while ($stmt->fetch(PDO_FETCH_BOUND)) { echo "Extension: $extension\n"; echo "Author: $name\n"; }}
![Page 43: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/43.jpg)
Portability Aids
• PDO aims to make it easier to write db independent apps
• Number of hacks^Wtweaks for this purpose
![Page 44: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/44.jpg)
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
![Page 45: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/45.jpg)
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);
![Page 46: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/46.jpg)
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
![Page 47: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/47.jpg)
PDO_ERRMODE_SILENT
if (!$dbh->query($sql)) { echo $dbh->errorCode() . "<br>"; $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}
![Page 48: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/48.jpg)
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
![Page 49: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/49.jpg)
PDO_ERRMODE_EXCEPTIONtry { $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}
![Page 50: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/50.jpg)
Transactions
$dbh->beginTransaction();try { $dbh->query("UPDATE ..."); $dbh->query("UPDATE ..."); $dbh->commit();} catch (Exception $e) { $dbh->rollBack();}
![Page 51: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/51.jpg)
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
![Page 52: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/52.jpg)
Fetching an image
$db = new PDO($dsn);
$stmt = $db->prepare(
“select contenttype, imagedata”
.“ from images where id=?”);
$stmt->execute(array($_GET['id']));
list($type, $lob) = $stmt->fetch();
header("Content-Type: $type");
fpassthru($lob);
![Page 53: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/53.jpg)
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();
![Page 54: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/54.jpg)
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)
![Page 55: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/55.jpg)
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
![Page 56: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/56.jpg)
Multi-rowset queries
$stmt = $dbh->query(
"call sp_multi_results()");
do {
while($row = $stmt->fetch()) {
print_r($row);
}
} while ($stmt->nextRowset());
![Page 57: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/57.jpg)
Questions?
![Page 58: PHP Data Objects](https://reader030.vdocuments.site/reader030/viewer/2022013101/56814de7550346895dbb5816/html5/thumbnails/58.jpg)
Resources
• The PHP Manual: http://php.net/pdo• Publications
– www-128.ibm.com/developerworks/db2/library/techarticle/dm-0505furlong/
– www.oracle.com/technology/pub/articles/php_experts/otn_pdo_oracle5.html
• My blog: http://netevil.org• Bugs: http://bugs.php.net