From 2649bceb68261cdfb02231e9fa7af68f44402b90 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Sun, 11 Sep 2005 21:10:36 +0000 Subject: [PATCH] Add some content. git-svn-id: https://svn.php.net/repository/phpdoc/en/trunk@195828 c90b9560-bf6c-de11-be94-00142212c4b1 --- reference/pdo/reference.xml | 526 +++++++++++++++++++++++++++++++++++- 1 file changed, 525 insertions(+), 1 deletion(-) diff --git a/reference/pdo/reference.xml b/reference/pdo/reference.xml index 0ba7d42325..0b94d85552 100644 --- a/reference/pdo/reference.xml +++ b/reference/pdo/reference.xml @@ -1,5 +1,5 @@ - + @@ -20,6 +20,14 @@ itself; you must use a database-specific PDO driver to access a database server. + + PDO provides a data-access abstraction layer, which + means that, regardless of which database you're using, you use the same + functions to issue queries and fetch data. PDO does + not provide a database + abstraction; it doesn't rewrite SQL or emulate missing features. You + should use a full-blown abstraction layer for PDO. + PDO ships with PHP 5.1, and is available as a PECL extension for PHP 5.0; PDO requires the new OO features in the core of PHP 5, and so will not @@ -216,6 +224,522 @@ extension=php_pdo_sqlite.dll +
+ Connections and Connection management + + Connections are established by creating instances of the PDO base class. + It doesn't matter which driver you want to use; you always use the PDO + class name. The constructor accepts parameters for specifying the + database source (known as the DSN) and optionally for the username and + password (if any). + + + Connecting to mysql + + +]]> + + + + + If there are any connection errors, a PDOException + object will be thrown. You may catch the exception if you want to handle + the error condition, or you may opt to leave it for an application + global exception handler that you set up via + set_exception_handler. + + + Handling connection errors + +query('SELECT * from FOO') as $row) { + print_r($row); + } + $dbh = null; +} catch (PDOException $e) { + print "Error!: " . $e->getMessage() . "
"; + die(); +} +?> +]]> +
+
+
+ + Upon successful connection to the database, an instance of the PDO class + is returned to your script. The connection remains active for the + lifetime of that PDO object. To close the connection, you need to + destroy the object by ensuring that all remaining references to it are + deleted--you do this by assigning &null; to the variable that holds the + object. If you don't do this explicitly, PHP will automatically close + the connection when your script ends. + + + Closing a connection + + +]]> + + + + + Many web applications will benefit from making persistent connections to + database servers. Persistent connections are not closed at the end of the + script, but are cached and re-used when another script requests a + connection using the same credentials. The persistent connection cache + allows you to avoid the overhead of establishing a new connection every + time a script needs to talk to a database, resulting in a faster web + application. + + + Persistent connections + + true +)); +]]> + + + + + + If you're using the PDO ODBC driver and your ODBC libraries support ODBC + Connection Pooling (unixODBC and Windows are two that do; there may be + more), then it's recommended that you don't use persistent PDO + connections, and instead leave the connection caching to the ODBC + Connection Pooling layer. The ODBC Connection Pool is shared with other + modules in the process; if PDO is told to cache the connection, then + that connection would never be returned to the ODBC connection pool, + resulting in additional connections being created to service those other + modules. + + +
+ +
+ Transactions and auto-commit + + Now that you're connected via PDO, you should to understand how PDO + manages transactions before you start issuing queries. If you've never + encountered transactions before, they offer 4 major features: Atomicity, + Consistency, Isolation and Durability (ACID). In layman's terms, any work + carried out in a transaction, even if it is carried out in stages, is + guaranteed to be applied to the database safely, and without interference + from other connections, when it is committed. Transactional work can also + be automatically undone at your request (provided you haven't already + committed it), which makes error handling in your scripts easier. + + + Transactions are typically implemented by "saving-up" your batch of + changes to be applied all at once; this has the nice side effect of + drastically improving the efficiency of those updates. In other words, + transactions can make your scripts faster and potentially more robust + (you still need to use them correctly to reap that benefit). + + + Unfortunately, not every database supports transactions, so PDO needs to + run in what is known as "auto-commit" mode when you first open the + connection. Auto-commit mode means that every query that you run has its + own implicit transaction, if the database supports it, or no transaction + if the database doesn't support transactions. If you need a transaction, + you must use the PDO::beginTransaction method to + initiate one. If the underlying driver does not support transactions, a + PDOException will be thrown (regardless of your error handling settings: + this is always a serious error condition). Once you are in a transaction, + you may use PDO::commit or + PDO::rollBack to finish it, depending on the success + of the code you run during the transaction. + + + + When the script ends or when a connection is about to be closed, if you + have an outstanding transaction, PDO will automatically roll it back. + This is a safety measure to help avoid inconsistency in the cases where + the script terminates unexpectedly--if you didn't explicitly commit the + transaction, then it is assumed that something went awry, so the rollback + is performed for the safety of your data. + + + + The automatic rollback only happens if you initiate the transaction via + PDO::beginTransaction. If you manually issue a + query that begins a transaction PDO has no way of knowing about it and + thus cannot roll it back if something bad happens. + + + + Executing a batch in a transaction + + In the following sample, let's assume that we are creating a set of + entries for a new employee, who has been assigned an ID number of 23. + In addition to entering the basic data for that person, we also need to + record their salary. It's pretty simple to make two separate updates, + but by enclosing them within the + PDO::beginTransaction and + PDO::commit calls, we are guaranteeing that no one + else will be able to see those changes until they are complete. If + something goes wrong, the catch block rolls back all changes made + since the transaction was started, and then prints out an error + message. + + + true)); + echo "Connected\n"; + $dbh->setAttribute(PDO_ATTR_ERRMODE, PDO_ERRMODE_EXCEPTION); + + $dbh->beginTransaction(); + $dbh->exec("insert into staff (id, first, last) values (23, 'Joe', 'Bloggs')"); + $dbh->exec("insert into salarychange (id, amount, changedate) + values (23, 50000, NOW())"); + $dbh->commit(); + +} catch (Exception $e) { + $dbh->rollBack(); + echo "Failed: " . $e->getMessage(); +} +?> +]]> + + + + + You're not limited to making updates in a transaction; you can also issue + complex queries to extract data, and possibly use that information to + build up more updates and queries; while the transaction is active, you + are guaranteed that no one else can make changes while you are in the + middle of your work. In truth, this isn't 100% correct, but it is a + good-enough introduction, if you've never heard of transactions before. + +
+ +
+ Prepared statements and stored procedures + + Many of the more mature databases support the concept of prepared + statements. What are they? You can think of them as a kind of compiled + template for the SQL that you want to run, that can be customized using + variable parameters. Prepared statements offer two major benefits: + + + + + The query only needs to be parsed (or prepared) once, but can be + executed multiple times with the same or different parameters. When the + query is prepared, the database will analyze, compile and optimize it's + plan for executing the query. For complex queries this process can take + up enough time that it will noticably slow down your application if you + need to repeat the same query many times with different parameters. By + using a prepared statement you avoid repeating the + analyze/compile/optimize cycle. In short, prepared statements use fewer + resources and thus run faster. + + + + + The parameters to prepared statements don't need to be quoted; the + driver handles it for you. If your application exclusively uses + prepared statements, you can be sure that no SQL injection will occur. + (However, if you're still building up other parts of the query based on + untrusted input, you're still at risk). + + + + + Prepared statements are so useful that they are the only feature that PDO + will emulate for drivers that don't support them. This ensures that you + will be able to use the same data access paradigm regardless of the + capabilities of the database. + + + Repeated inserts using prepared statements + + This example performs an INSERT query by substituting a name + and a value for the named placeholders. + + +prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)"); +$stmt->bindParam(':name', $name); +$stmt->bindParam(':value', $value); + +// insert one row +$name = 'one'; +$value = 1; +$stmt->execute(); + +// insert another row with different values +$name = 'two'; +$value = 2; +$stmt->execute(); +?> +]]> + + + + + Repeated inserts using prepared statements + + This example performs an INSERT query by substituting a name + and a value for the positional ? placeholders. + + +prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)"); +$stmt->bindParam(1, $name); +$stmt->bindParam(2, $value); + +// insert one row +$name = 'one'; +$value = 1; +$stmt->execute(); + +// insert another row with different values +$name = 'two'; +$value = 2; +$stmt->execute(); +?> +]]> + + + + + Fetching data using prepared statements + + This example fetches data based on a key value supplied by a form. + The user input is automatically quoted, so there is no risk of a + SQL injection attack. + + +prepare("SELECT * FROM REGISTRY where name = ?"); +if ($stmt->execute(array($_GET['name']))) { + while ($row = $stmt->fetch()) { + print_r($row); + } +} +?> +]]> + + + + + If the database driver supports it, you may also bind parameters for + output as well as input. Output parameters are typically used to retrieve + values from stored procedures. Output parameters are slightly more complex + to use than input parameters, in that you must know how large a given + parameter might be when you bind it. If the value turns out to be larger + than the size you suggested, an error is raised. + + + + Calling a stored procedure with an output parameter + +prepare("CALL sp_returns_string(?)"); +$stmt->bindParam(1, $return_value, PDO_PARAM_STR, 4000); + +// call the stored procedure +$stmt->execute(); + +print "procedure returned $return_value\n"; +?> +]]> + + + + + + You may also specify parameters that hold values both input and output; + the syntax is similar to output parameters. In this next example, the + string 'hello' is passed into the stored procedure, and when it returns, + hello is replaced with the return value of the procedure. + + + + Calling a stored procedure with an input/output parameter + +prepare("CALL sp_takes_string_returns_string(?)"); +$value = 'hello'; +$stmt->bindParam(1, $value, PDO_PARAM_STR|PDO_PARAM_INPUT_OUTPUT, 4000); + +// call the stored procedure +$stmt->execute(); + +print "procedure returned $value\n"; +?> +]]> + + + +
+ +
+ Errors and error handling + + PDO offers you a choice of 3 different error handling strategies, to fit + your style of application development. + + + + + PDO_ERRMODE_SILENT + + + This is the default mode. PDO will simply set the error code for you + to inspect using the PDO::errorCode and + PDO::errorInfo methods on both the + statement and database objects; if the error resulted from a call on a + statement object, you would invoke the + PDOStatement::errorCode or + PDOStatement::errorInfo + method on that object. If the error resulted from a call on the + database object, you would invoke those methods on the database object + instead. + + + + + PDO_ERRMODE_WARNING + + + In addition to setting the error code, PDO will emit a traditional + E_WARNING message. This setting is useful during debugging/testing, if + you just want to see what problems occurred without interrupting the + flow of the application. + + + + + PDO_ERRMODE_EXCEPTION + + + In addition to setting the error code, PDO will throw a PDOException + and set its properties to reflect the error code and error + information. This setting is also useful during debugging, as it will + effectively "blow up" the script at the point of the error, very + quickly pointing a finger at potential problem areas in your code + (remember: transactions are automatically rolled back if the exception + causes the script to terminate). + + + Exception mode is also useful because you can structure your error + handling more clearly than with traditional PHP-style warnings, and + with less code/nesting than by running in silent mode and explicitly + checking the return value of each database call. + + + + + PDO standardizes on using SQL-92 SQLSTATE error code strings; individual + PDO drivers are responsible for mapping their native codes to the + appropriate SQLSTATE codes. The PDO::errorCode + method returns a single SQLSTATE code. If you need more specific + information about an error, PDO also offers an + PDO::errorInfo method which returns an array + containing the SQLSTATE code, the driver specific error code and driver + specific error string. + +
+ +
+ Large Objects (LOBs) + + At some point in your application, you might find that you need to store + "large" data in your database. Large typically means "around 4kb or + more", although some databases can happily handle up to 32kb before data becomes + "large". Large objects can be either textual or binary in nature. PDO + allows you to work with this large data type by using the PDO_PARAM_LOB + type code in your PDOStatement::bindParam or + PDOStatement::bindColumn calls. PDO_PARAM_LOB tells + PDO to map the data as a stream, so that you can manipulate it using the + PHP Streams API. + + + + + + Displaying an image from a database + + This example binds the LOB into the variable named $lob and then sends + it to the browser using fpassthru. Since the LOB + is represented as a stream, functions such as + fgets, fread and + stream_get_contents can be used on it. + + +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("Content-Type: $type"); +fpassthru($lob); +?> +]]> + + + + + Inserting an image into a database + + This example opens up a file and passes the file handle to PDO to insert + it as a LOB. PDO will do its best to get the contents of the file up + to the database in the most efficient manner possible. + + +prepare("insert into images (id, contenttype, imagedata) values (?, ?, ?)"); +$id = get_new_id(); // some function to allocate a new ID + +// assume that we are running as part of a file upload form +// You can find more information in the PHP documentation + +$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(); +?> +]]> + + + +
+
&reftitle.classes;