wez             Sun Sep 11 17:10:37 2005 EDT

  Modified files:              
    /phpdoc/en/reference/pdo    reference.xml 
  Log:
  Add some content.
  
  
http://cvs.php.net/diff.php/phpdoc/en/reference/pdo/reference.xml?r1=1.35&r2=1.36&ty=u
Index: phpdoc/en/reference/pdo/reference.xml
diff -u phpdoc/en/reference/pdo/reference.xml:1.35 
phpdoc/en/reference/pdo/reference.xml:1.36
--- phpdoc/en/reference/pdo/reference.xml:1.35  Sun Sep 11 03:22:22 2005
+++ phpdoc/en/reference/pdo/reference.xml       Sun Sep 11 17:10:36 2005
@@ -1,5 +1,5 @@
 <?xml version='1.0' encoding='iso-8859-1'?>
-<!-- $Revision: 1.35 $ -->
+<!-- $Revision: 1.36 $ -->
 <!-- Purpose: database.abstract -->
 <!-- Membership: pecl, bundled -->
 <!-- State:experimental -->
@@ -21,6 +21,14 @@
      PDO driver</link> to access a database server.
     </para>
     <para>
+     PDO provides a <emphasis>data-access</emphasis> 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
+     <emphasis>not</emphasis> provide a <emphasis>database</emphasis>
+     abstraction; it doesn't rewrite SQL or emulate missing features.  You
+     should use a full-blown abstraction layer for PDO.
+    </para>
+    <para>
      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
      run with earlier versions of PHP.
@@ -216,6 +224,522 @@
     </para>
    </section>
 
+   <section id='pdo.connections'>
+    <title>Connections and Connection management</title>
+    <para>
+     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).
+    </para>
+    <para>
+     <example><title>Connecting to mysql</title>
+      <programlisting role='php'>
+<![CDATA[
+<?php
+$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
+?>
+]]> 
+      </programlisting>
+     </example>
+    </para>
+    <para>
+     If there are any connection errors, a <literal>PDOException</literal>
+     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
+     <function>set_exception_handler</function>.
+    </para>
+    <para>
+     <example><title>Handling connection errors</title>
+      <programlisting role='php'>
+<![CDATA[
+<?php
+try {
+   $dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
+   foreach ($dbh->query('SELECT * from FOO') as $row) {
+      print_r($row);
+   }
+   $dbh = null;
+} catch (PDOException $e) {
+   print "Error!: " . $e->getMessage() . "<br/>";
+   die();
+}
+?>
+]]>
+      </programlisting>
+     </example>
+    </para>
+    <para>
+     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.
+    </para>
+    <para>
+     <example><title>Closing a connection</title>
+     <programlisting role='php'>
+<![CDATA[
+<?php
+$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
+// use the connection here
+
+
+// and now we're done; close it
+$dbh = null;
+?>
+]]>
+     </programlisting>
+    </example>
+   </para>
+   <para>
+    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.
+   </para>
+   <para>
+    <example><title>Persistent connections</title>
+     <programlisting role='php'>
+<![CDATA[
+<?php
+$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(
+  PDO_ATTR_PERSISTENT => true
+));
+]]>
+     </programlisting>
+     </example>
+    </para>
+    <note>
+     <para>
+      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.
+     </para>
+    </note>
+   </section>
+
+   <section id='pdo.transactions'>
+    <title>Transactions and auto-commit</title>
+    <para>
+     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.
+    </para>
+    <para>
+     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).
+    </para>
+    <para>
+     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 <function>PDO::beginTransaction</function> 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 <function>PDO::commit</function> or
+     <function>PDO::rollBack</function> to finish it, depending on the success
+     of the code you run during the transaction.
+
+    </para>
+    <para>
+     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.
+    </para>
+    <warning>
+     <para>
+      The automatic rollback only happens if you initiate the transaction via
+      <function>PDO::beginTransaction</function>. 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.
+     </para>
+    </warning>
+    <para>
+     <example><title>Executing a batch in a transaction</title>
+      <para>
+       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
+       <function>PDO::beginTransaction</function> and
+       <function>PDO::commit</function> 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.
+      </para>
+      <programlisting role='php'>
+<![CDATA[
+<?php
+try {
+  $dbh = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2', 
+      array(PDO_ATTR_PERSISTENT => 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();
+}
+?>
+]]>
+      </programlisting>
+     </example>
+    </para>
+    <para>
+     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.
+    </para>
+   </section>
+
+   <section id='pdo.prepared-statements'>
+    <title>Prepared statements and stored procedures</title>
+    <para>
+     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:
+    </para>
+    <itemizedlist>
+     <listitem>
+      <simpara>
+       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.
+      </simpara>
+     </listitem>
+     <listitem>
+      <simpara>
+       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).
+      </simpara>
+     </listitem>
+    </itemizedlist>
+    <para>
+     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.
+    </para>
+    <para>
+     <example><title>Repeated inserts using prepared statements</title>
+     <simpara>
+      This example performs an INSERT query by substituting a 
<literal>name</literal>
+      and a <literal>value</literal> for the named placeholders.
+     </simpara>
+     <programlisting role='php'>
+<![CDATA[
+<?php
+$stmt = $dbh->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();
+?>
+]]>
+     </programlisting>
+    </example>
+   </para>
+    <para>
+     <example><title>Repeated inserts using prepared statements</title>
+     <simpara>
+      This example performs an INSERT query by substituting a 
<literal>name</literal>
+      and a <literal>value</literal> for the positional <literal>?</literal> 
placeholders.
+     </simpara>
+     <programlisting role='php'>
+<![CDATA[
+<?php
+$stmt = $dbh->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();
+?>
+]]>
+     </programlisting>
+    </example>
+   </para>
+    <para>
+     <example><title>Fetching data using prepared statements</title>
+     <simpara>
+      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.
+     </simpara>
+     <programlisting role='php'>
+<![CDATA[
+<?php
+$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?");
+if ($stmt->execute(array($_GET['name']))) {
+  while ($row = $stmt->fetch()) {
+    print_r($row);
+  }
+}
+?>
+]]>
+     </programlisting>
+    </example>
+   </para>
+   <para>
+    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.
+   </para>
+
+   <para>
+    <example><title>Calling a stored procedure with an output parameter</title>
+     <programlisting role='php'>
+<![CDATA[
+<?php
+$stmt = $dbh->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";
+?>
+]]>
+     </programlisting>
+    </example>
+   </para>
+
+   <para>
+    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.
+   </para>
+
+   <para>
+    <example><title>Calling a stored procedure with an input/output 
parameter</title>
+     <programlisting role='php'>
+<![CDATA[
+<?php
+$stmt = $dbh->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";
+?>
+]]>
+     </programlisting>
+    </example>
+   </para>
+  </section>
+
+  <section id='pdo.error-handling'>
+   <title>Errors and error handling</title>
+    <para>
+     PDO offers you a choice of 3 different error handling strategies, to fit
+     your style of application development.
+    </para>
+    <itemizedlist>
+     <listitem>
+      <para>
+       PDO_ERRMODE_SILENT
+      </para>
+      <para>
+        This is the default mode. PDO will simply set the error code for you
+        to inspect using the <function>PDO::errorCode</function> and
+        <function>PDO::errorInfo</function> methods on both the
+        statement and database objects; if the error resulted from a call on a
+        statement object, you would invoke the
+        <function>PDOStatement::errorCode</function> or
+        <function>PDOStatement::errorInfo</function>
+        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.
+       </para>
+     </listitem>
+     <listitem>
+      <para>
+       PDO_ERRMODE_WARNING
+      </para>
+      <para>
+        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.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+        PDO_ERRMODE_EXCEPTION
+       </para>
+       <para>
+        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).
+      </para>
+      <para>
+        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.
+       </para>
+      </listitem>
+    </itemizedlist>
+    <para>
+     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 <function>PDO::errorCode</function>
+     method returns a single SQLSTATE code. If you need more specific
+     information about an error, PDO also offers an
+     <function>PDO::errorInfo</function> method which returns an array
+     containing the SQLSTATE code, the driver specific error code and driver
+     specific error string.
+    </para>
+   </section>
+
+   <section id='pdo.lobs'>
+    <title>Large Objects (LOBs)</title>
+    <para>
+      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 <function>PDOStatement::bindParam</function> or
+      <function>PDOStatement::bindColumn</function> calls. PDO_PARAM_LOB tells
+      PDO to map the data as a stream, so that you can manipulate it using the
+      <link linkend='ref.stream'>PHP Streams API</link>.
+    </para>
+    <para>
+     
+    </para>
+    <para>
+     <example><title>Displaying an image from a database</title>
+     <para>
+      This example binds the LOB into the variable named $lob and then sends
+      it to the browser using <function>fpassthru</function>.  Since the LOB
+      is represented as a stream, functions such as
+      <function>fgets</function>, <function>fread</function> and
+      <function>stream_get_contents</function> can be used on it.
+     </para>
+     <programlisting role='php'>
+<![CDATA[
+<?php
+$db = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2');
+$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("Content-Type: $type");
+fpassthru($lob);
+?>
+]]>
+     </programlisting>
+    </example>
+   </para>
+   <para>
+    <example><title>Inserting an image into a database</title>
+     <para>
+      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.
+     </para>
+     <programlisting role='php'>
+<![CDATA[
+<?php
+$db = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2');
+$stmt = $db->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();
+?>
+]]>
+     </programlisting>
+     </example>
+    </para>
+   </section>
+
    <section id='pdo.classes'>
     &reftitle.classes;
     <section id='pdo.class.PDO'>

Reply via email to