Lukas Smith database abstraction layers in PHP BackendMedia 1
Overview Introduction Motivation PDO extension PEAR::MDB2 Client API SQL syntax SQL concepts Result sets Error handling High level features 2
Motivation Support for multiple RDBMS Forward compatibility new RDBMS versions new PHP (extension) versions (MySQLi/PDO) Vendor Lock in Train costs Pushing your own preference to the client Higher level API 3
PDO Extension C Extension OO Interface Driver model Client API Unification Planned for PHP 5.1 Iterators Marked with! 4
PEAR::MDB2 (1/2) OO Interface Driver model Compatible with PHP4 and PHP5 PDO API compatible (eventually) On demand loading of advanced features Portability mode optional PEAR_Error and debug capabilities Iterators 5
PEAR::MDB2 (2/2) Installation: $> pear install MDB2-beta $> pear install MDB2_Schema-beta Already in production (planet-php.org) MDB was a merge of Metabase and DB MDB2 consolidates this merge MDB2 is much faster than as Metabase, faster than DB, and as fast as ADODB (*) Marked with!» (*) all benchmarks lie! 6
Client API Differences between RDBMS extensions Example: connect to RDBMS (!!): ibase_pconnect()/ibase_connect() OCIPLogon()/OCILogon() sqlite_popen()/sqlite_open() Example: sending SQL to the server (!!): OCIExecute() mysql_query()/mysql_unbuffered_query() pg_exec() Preference for an OO API (!!) 7
SQL syntax (1/5) SELECT LIMIT (!) Missing in some RDBMS (like Oracle) Syntax differences // set limit $db->setlimit(10, 20); REPLACE (!) Only exists in MySQL and SQLite TRANSACTIONS Missing in some RDBMS (MySQL with MyISAM) Syntax differences (!!) 8
SQL syntax (2/5) SUBSELECT (!) Missing in some RDBMS (z.b. MySQL < 4.x) $sql = 'SELECT name FROM foo WHERE id ='. $db->quote(mdb2_date::now(), 'time'); // subselect $subselect = $db->subselect($sql, 'text'); // sql string $sql = 'SELECT is_active FROM bar WHERE id IN ('.$subselect.')'; // send off query $res = $db->query($sql, 'boolean'); 9
SQL syntax (3/5) Data types (!) Date (!) Boolean (!) Decimal (!) Float (!) LOB (!!) $db->quote($text, text'); $db->quote($date, timestamp'); $db->quote($bool, boolean'); $db->quote($fp, blob'); 10
SQL syntax (4/5) Schema Management (!) CREATE Database Table Field Index Sequence ALTER TABLE SHOW Databases Tables Indexes Sequences Views Functions 11
SQL syntax (5/5) SQL functions Function names: SUBSTR() vs. SUBSTRING() Parameter order Offset count starts at 0 or 1 Stored Procedures Client API Syntax Very hard to do Requires using a meta programming language (MetaL) 12
SQL concepts (1/5) Sequences vs. auto increment Sequences can emulate auto increment (!) Auto increment can only emulate sequences with a query builder $id = $db->getbeforeid($table); $sql = INSERT INTO $table (.$db- >quote($id, 'integer').', 'foo')'; $db->query($sql); $id = $mdb2->getafterid($id, $table); 13
SQL concepts (2/5) Prepared statements:? placeholder (!!) // create sql string $sql = 'INSERT INTO foo (?,?,?)'; // send off query $types = array('text', 'decimal', 'blob') $stmt = $db->prepare($sql, $types); // bind values $stmt->bindparam(0, $text); $stmt->bindparam(1, $decimal); $stmt->bindparam(2, $fp); 14
SQL concepts (3/5) Prepared statements: named parameters (!!) // create sql string $sql = 'INSERT INTO foo (:url, :dm, :file)'; // send off query $types = array('text', 'decimal', 'blob') $stmt = $db->prepare($sql, $types); // bind values $stmt->bindparam( url', $text); $stmt->bindparam( dm', $decimal); $stmt->bindparam( file', $fp); 15
SQL concepts (4/5) Execute statement (!!) // send off query $result = $stmt->execute(); // bind next set of data $text = 'foo'; $decimal = 23453/8; $fp = 'bar.pdf'; // send off query $result = $stmt->execute(); 16
SQL concepts (5/5) Database (!) Foreign keys / Trigger Only possible with a query builder VIEWS Only possible with a query builder User management Some what doable 17
Result sets (Un-)Buffered (!!) NULL vs. empty strings (!!) Associative fetches (!!) Padded strings (!!) Introspection (!!) Data types (!) // create sql string $sql = 'SELECT datebirth, decmoney FROM foo'; // send off query $types = array( date', 'float') $res = $db->query($sql, $types); 18
Error handling Different error codes or no support for error codes Error codes (!!) Connection errors Syntactical errors Semantic errors Access violations etc. 19
High level features (1/3) XML schema (!) CREATE and ALTER statement generation User defined data types (!) Serialize PEAR Error (!) PEAR::expectError() PEAR::setErrorHandling() Exceptions Native (option) (!) Via callback (!) 20
High level features (2/3) // expect no such table error $db->expecterror(mdb2_error_nosuchtable); // send off query, fetch all data and rekey $res = $db->queryall($sql, $types, MDB2_FETCHMODE_ASSOC, true); $db->popexpect(); // table didnt exist? if (MDB2::isError($res, MDB2_ERROR_NOSUCHTABLE) {..} 21
High level features (3/3) fetchall() (!!) Read all rows of a result set into a multi dimensional array all at once Result buffering Rekey (!!) Use the first column as the key for the first array dimension instead of the row number Grouping (!!) All rows with the same value in the first column are grouped inside another array 22
Thank you for your attention! Questions? Feedback? 23