1. 简介这是一部指导我们如何使用Pear DB扩展。Pear DB,提供这样一系列的类:
n 数据库抽象
n 高级错误处理机制
n 以及其它
2. 下载、安装Pear 由于现在Pear项目仍处于紧锣密鼓的开发之中,所以得到它的最好办法就是从CVS获得(Pear DB发行包已经跟随PHP4.0.6以后版本捆绑发布)。所以,我们只需要把Pear的根目录放到php.ini配置文件include_path中。也可以通过这样设置:
_set('include_path', '/pear_base_dir').
以下是strp by step示例:
存放Pear的目录: # cd /usr/local/lib 用“phpfi“口令登录: # cvs -d :pserver:cvsread@cvs.php.net:/repository login 用以下命令得到所有的pear文件,同时也可以用来更新已经下载的文件。其他的参数有:"today", "last month",等。我推荐用"last week"参数,因为一般bugs的提交和修改都是每周一次。 # cvs -d :pserver:cvsread@cvs.php.net:/repository export -D "last week" php4/pear 编辑php.ini文件加上下面一段在include_path处: /usr/local/lib/php4/pear 如果没有修改的权限,可以通过这条语句在代码中实现: ini_set('include_path', 'path_to_pear'); |
获得PHP CVS的完全文档
注意Pear DB必需PHP版本4.0.4以上,而在Pear中的一些其他包如:XML Parser of the pear installer script需要PHP4.0.5以上版本。
3. 使用Pear DB
3.1 连接,断开数据库
<?php // The pear base directory must be in your include_path require_once 'DB.php' ; $user = 'foo' ; $pass = 'bar' ; $host = 'localhost' ; $db_name = 'clients_db' ;
// Data Source Name: This is the universal connection string $dsn = "mysql://$user:$pass@$host/$db_name" ;
// DB::connect will return a Pear DB object on success // or a Pear DB Error object on error // You can also set to TRUE the second param // if you want a persistent connection: // $db = DB::connect($dsn, true); $db = DB :: connect ( $dsn );
// With DB::isError you can differentiate between an error or // a valid connection. if ( DB :: isError ( $db )) { die ( $db -> getMessage ()); } .... // You can disconnect from the database with: $db -> disconnect (); ?>
|
数据源(上例中的$dsn 参数)有以下允许的格式:(从Pear/DB.php的parseDSN方法复制而来)
* phptype: Database backend used in PHP (mysql, odbc etc.) * dbsyntax: Database used with regards to SQL syntax etc. * protocol: Communication protocol to use (tcp, unix etc.) * hostspec: Host specification (hostname[:port]) * database: Database to use on the DBMS server * username: User name for login * password: Password for login * * The format of the supplied DSN is in its fullest form: * * phptype(dbsyntax)://username:password@protocol+hostspec/database * * Most variations are allowed: * * phptype://username:password@protocol+hostspec:110//usr/db_file.db * phptype://username:password@hostspec/database_name * phptype://username:password@hostspec * phptype://username@hostspec * phptype://hostspec/database * phptype://hostspec * phptype(dbsyntax) * phptype
|
现在支持的数据库有 (在 phptype DSN 部分):
mysql -> MySQL pgsql -> PostgreSQL ibase -> InterBase msql -> Mini SQL mssql -> Microsoft SQL Server oci8 -> Oracle 7/8/8i odbc -> ODBC (Open Database Connectivity) sybase -> SyBase ifx -> Informix fbsql -> FrontBase
|
注意并不是所有数据库特征都支持,可以从根目录>/DB/STATUS 得到详细的清单。
3.2 执行数据库
<?php // Once you have a valid DB object ... $sql = "select * from clients" ; // If the query is a "SELECT", $db->query will return // a DB Result object on success. // Else it simply will return a DB_OK // On failure it will return a DB Error object. $result = $db -> query ( $sql ); // Always check that $result is not an error if ( DB :: isError ( $result )) { die ( $result -> getMessage ()); } .... ?>
|
3.3 获得select的数据
3.3.1 获取数据的函数
<?php // Once you have a valid DB Result object ... // Get each row of data on each iteration until // there is no more rows while ( $row = $result -> fetchRow ()) { $id = $row [ 0 ]; } ?>
|
除了fetchRow()还可以使用fetchInto()直接插入$row的值。
<?php ... while ( $result -> fetchInto ( $row )) { $id = $row [ 0 ]; } ?>
|
3.3.2 选择获取数据的格式
获取模式有DB_FETCHMODE_ORDERED(默认), DB_FETCHMODE_ASSOC and DB_FETCHMODE_OBJECT.
从获取数据方法返回的结果示例:
<?php $res = $db -> query ( 'select id, name, email from users' ); $row = $res -> fetchRow ( $mode );
//With $mode = DB_FETCHMODE_ORDERED //The default behavior is to return an ordered array. $row = array ( 0 => < column "id" data >, 1 => < column "name" data >, 2 => < column "email" data > );
$id = $row [ 0 ];
//With $mode = DB_FETCHMODE_ASSOC //Returns an associative array with column names as array keys: $row = array ( 'id' => < column "id" data >, 'name' => < column "name" data >, 'email' => < column "email" data > );
$id = $row [ 'id' ];
//With $mode = DB_FETCHMODE_OBJECT //Returns a DB_row object with column names as properties: $row = db_row Object ( [ id ] => < column "id" data >, [ name ] => < column "name" data >, [ email ] => < column "email" data > )
$id = $row -> id ; ?>
|
3.3.3 设置获取数据的格式
可以使用 fetchrow() / fetchInto() 方法或者为你的DB实例设置一个默认的模式。
<?php ... // 1) Set the mode per call: while ( $row = $result -> fetchRow ( DB_FETCHMODE_ASSOC )) { [..] } while ( $result -> fetchInto ( $row , DB_FETCHMODE_ASSOC )) { [..] }
// 2) Set the mode for all calls: $db = DB :: connect ( $dsn ); // this will set a default fetchmode for this Pear DB instance // (for all queries) $db -> setFetchMode ( DB_FETCHMODE_ASSOC ); $result = $db -> query (...); while ( $row = $result -> fetchRow ()) { $id = $row [ 'id' ]; } ?>
|
3.3.4 控制获取数据数量
同时Pear DB获取数据可以带有额外的参数,可以使用一个数字参数来获取需要的数据数量。在你只需要获得数据中的一部分时这时候特别有用(比如在做分页程序的时候)
<?php ... // the row to start fetching $from = 50 ; // how many results per page $res_per_page = 10 ; // the last row to fetch for this page $to = $from + $res_per_page ; foreach ( range ( $from , $to ) as $rownum ) { if (! $row = $res -> fetchrow ( $fetchmode , $rownum )) { break; } $id = $row [ 0 ]; .... } ?>
|
3.3.5 清除结果,释放变量
当你完成查询的时候,可以用free()方法来结束:
<?php ... $result = $db -> query ( 'SELECT * FROM clients' ); while ( $row = $result -> fetchRow ()) { ... } $result -> free (); ?>
|
3.4 快速retrieve数据
当你不再想用fetchRow()方法来获取数据的时候,Pear DB通过sql语句提供一些特别的方法来返回想要的数据。这些方法有:getOne, getRow, getCol, getAssoc and getAll. 这有一些使用示例:
<?php require_once 'DB.php' ; $db = DB :: connect ( 'pgsql://postgres@unix+localhost/clients_db' ); // ----------------------------------------------------------- // getOne retrieves the first result of the first column // from a query $numrows = $db -> getOne ( 'select count(id) from clients' ); // ----------------------------------------------------------- // getRow will fetch the first row and return it as an array $sql = 'select name, address, phone from clients where id=1' ; if ( is_array ( $row = $db -> getRow ( $sql ))) { list( $name , $address , $phone ) = $row ; } // ----------------------------------------------------------- // getCol will return an array with the data of the // selected column. It accepts the column number to retrieve // as the second param. // The next sentence could return for example: // $all_client_names = array('Stig', 'Jon', 'Colin'); $all_client_names = $db -> getCol ( 'select name from clients' ); // ----------------------------------------------------------- // Other functions are: getAssoc() and getAll(). // For the moment refer to their in-line documentation // at pear/DB/common.php // ----------------------------------------------------------- ?>
|
"get*() 系列方法" 可以为你做很多事情, 包括: 发起一个查询, 获取数据和清除结果。请注意所有的Pear DB函数将可能返回一个 Pear DB_error 对象。
3.5 从查询结果获得更多信息(numRows, numCols, affectedRows, tableInfo)
通过 Pear DB可以从查询结果获得更多有用的数据信息 。这些方法有:
- numRows(): 通过一个"SELECT" 查询返回所有数据的数量。
- numCols():通过一个"SELECT" 查询返回所有的列。
- affectedRows(): 通过("INSERT", "UPDATE" or "DELETE")操作返回所有受影响的数据行数。
- tableInfo():通过一个"SELECT" 查询返回一个包含数据信息的数组。
示例:
<?php ... $db = DB :: connect ( $dsn ); $sql = 'select * from clients' ; $res = $db -> query ( $sql ); // Don't forget to check if the returned result from your // action is a Pear Error object. If you get a error message // like 'DB_error: database not capable', means that // your database backend doesn't support this action. // // Number of rows echo $res -> numRows (); // Number of cols echo $res -> numCols (); // Table Info print_r ( $res -> tableInfo ()); // Affected rows $sql = "delete from clients" ; // remember that this statement won't return a result object $db -> query ( $sql ); echo 'I have deleted ' . $db -> affectedRows () . 'clients' ; ?>
|
3.6 自动增长(Sequences)
Sequences 为数据行提供独一无二的ID标识。如果熟悉MySQL之类的话,可以把它想象为AUTO_INCREMENT.它非常简单,首先你获取一个ID,然后在这个ID所在的行插入你所需要记录的数据。可以为你的表设置更多的Sequences,只需要保证在任何特殊的表中都使用一样的sequence就行。
<?php ... // Get an ID (if the sequence doesn't exist, it will be created) $id = $db -> nextID ( 'mySequence' );
// Use the ID in your INSERT query $res = $db -> query ( "INSERT INTO myTable (id,text) VALUES ($id,'foo')" ); ... ?>
|
3.7 Prepare & Execute/ExcuteMultiple
<?php // UNTESTED CODE !!! // // Example inserting data $alldata = array( array( 1 , 'one' , 'en' ), array( 2 , 'two' , 'to' ), array( 3 , 'three' , 'tre' ), array( 4 , 'four' , 'fire' ) ); $sth = $dbh -> prepare ( "INSERT INTO numbers VALUES( , , )" ); foreach ( $alldata as $row ) { $dbh -> execute ( $sth , $row ); } //Here's an example of a file placeholder: $myfile = "/tmp/image.jpg" ; $sth = $dbh -> prepare ( 'INSERT INTO images ( , &)' ); $dbh -> execute ( $sth , array( "this is me" , $myfile )); //After I commit a bugfix that I have on my laptop, you can use //parameter arrays in the getXxx methods too: $ver = $dbh -> getOne ( "SELECT stableversion FROM packages WHERE name = " , array( $package )); ?>
|
3.8 autoCommit, commit and rollback
4. 可用方法列表
<?php /* * From the DB_(driver) objects */ // get the object with, ie: $db = DB :: connect ( 'mysql://user:pass@localhost/my_db' ); // Set options $db -> setErrorHandling (); $db -> setFetchmode (); // Information $db -> affectedRows (); $db -> tableInfo (); // Database manipulation $db -> query (); // Data fetch $db -> nextId (); $db -> getOne (); $db -> getRow (); $db -> getCol (); $db -> getAssoc (); $db -> getAll (); // Place holders and execute related $db -> quote (); $db -> prepare (); $db -> execute (); $db -> executeMultiple (); // Transactions $db -> autoCommit (); $db -> commit (); $db -> rollback (); // Disconnection $db -> disconnect (); /* * From DB_result objects */ // get the object with, ie: $res = $db -> query ( 'select * from foo' ); // Data fetch $res -> fetchRow (); $res -> fetchInto (); // Result Info $res -> numCols (); $res -> numRows (); $res -> tableInfo (); // Free $res -> free (); /* * From DB_error objects */ // get the object with, ie: $error = $db -> query ( 'select * from no_table' ); $error -> getMessage (); $error -> getDebugInfo (); $error -> toString (); ?>
|
5. 错误处理机制
5.1. 从Pear DB Error获得错误信息
所有从Pear DB 返回的错误都是Pear Errors. 这有一种方法来搜集:
<?php ... $res = $db -> query ( 'select * from no_table' ); if ( DB :: isError ( $res )) { // get the portable error string echo $res -> getMessage (); } ?>
|
4.2 Debug Pear DB Errors
Pear DB采用一种轻便的错误消息系统向用户报错。把错误信息简单翻译成其它语言或者对于一种特殊错误采取特殊的处理方式这都带来了很大的优点。但是对于开发人员来说这些提示并么有提供很有用的信息。想要得到真实的数据处理出错的信息,你可以使用getDebugInfo()方法:
<?php $sql = 'select * from no_table' ; if ( DB :: isError ( $res = $db -> query ( $sql ))) { // get the native backend error // and the last query echo $res -> getDebugInfo (); } ?>
|
通过当一个PHP函数出错时,会打印出出错提示。在pear中的这种机制被屏蔽了。但时有时你可能需要在代码中捕捉一些错误信息。可以使用set_error_handler PHP 函数, 从 PHP Manual获取信息.简单示例:
<?php // what messages to report error_reporting ( E_ALL ^ E_NOTICE ); // this function will handle all reported errors function my_error_handler ( $errno , $errstr , $errfile , $errline ) { echo "In $errfile, line: $errline \n $errstr"
; } set_error_handler ( 'my_error_handler' ); $db = DB :: connect ( 'pgsql://postgres@localhost/no_db' ); ... ?>
|
5.3 对错误采取自动处理
正如你所看见的, Pear DB提供了广泛的错误检测和报告机制,这强迫开发人员必需对返回的数据结果进行检查,是否有错。 Pear DB同时照顾我们避免这种痛苦的工作,提供了一种灵活的体系,在一个错误出现的时候自动调用相应的措施。
这些可能的措施包括:
- 返回错误对象 (PEAR_ERROR_RETURN). 这是默认的.
- 打印错误 (PEAR_ERROR_PRINT)
- 打印错误信息并忽略执行(PEAR_ERROR_DIE)
- 用PHP函数 trigger_error()来列举错误(PEAR_ERROR_TRIGGER)
- 把错误对象传递给一个函数或者类的方法 (PEAR_ERROR_CALLBACK)
简单示例:
<?php require_once 'DB.php' ; // Set the default action to take on error PEAR :: setErrorHandling ( PEAR_ERROR_DIE ); // From here you don't need to check errors any more $db = DB :: connect ( 'pgsql://postgres@localhost/my_database' ); $res = $db -> query ( 'select id from no_table' ); // at this point the execution is aborted and the error message is raisen ... ?>
|
高级示例:
<?php // Define the app environment (this is: what errors you want to output) define ( 'DEBUG_ENV' , true ); // This function will handle all errors function handle_pear_error ( $error_obj ) { // Be verbose while developing the application if ( DEBUG_ENV ) { die ( $error_obj -> getMessage (). "\n" . $error_obj -> getDebugInfo ()); // Dump a silly message if the site is in production } else { die ( 'Sorry you request can not be processed now. Try again later' ); } }
require_once 'DB.php' ; // On error, call the "handle_pear_error" function back // You can also use an object as pear error handler so: // setErrorHandling(PEAR_ERROR_CALLBACK, array($object,'method_name'); PEAR :: setErrorHandling ( PEAR_ERROR_CALLBACK , 'handle_pear_error' ); $db = DB :: connect ( 'pgsql://postgres@localhost/site_db' ); $res = $db -> query ( 'select id from no_table' ); // at this point the execution is aborted and the "handle_pear_error" // function is called with the error object as its first argument while ( $row = $res -> fetchRow ()) { ... } ... ?>
|
下面为扩展错误机制提供了一个很好的想法:
<?php error_reporting ( E_ALL ^ E_NOTICE ); // this function will handle all errors reported by PHP function php_error_handler ( $errno , $errstr , $errfile , $errline ) { die ( "In $errfile, line: $errline \n $errstr"
); } set_error_handler ( 'php_error_handler' ); // this function will catch errors generated by Pear, // transform it to PHP errors and trigger them to the php_error_handler function pear_error_handler ( $err_obj ) { $error_string = $err_obj -> getMessage () . ' ' . $error_obj -> getDebugInfo (); trigger_error ( $error_string , E_USER_ERROR ); } require 'DB.php' ; PEAR :: setErrorHandling ( PEAR_ERROR_CALLBACK , 'pear_error_handler' ); // force an error $db = DB :: connect ( 'pgsql://postgres@localhost/no_db' ); ... ?>
|