php soap例項(一)無wsdl模式
現在企業越來越多用php做開發,當社會上培訓java的求職者氾濫時,尤其顯出phper的需求空缺。今天講解php做web開發的的七種武器篇,涉及web開發全過程,以供初學者學習。
做web開發很重要的一塊時和資料庫打交道。所以資料庫的連線層很重要。以前在面向過程開發時候自己寫mysql_connect() 連結資料庫,後來自己用類封裝mysql_connect(),最後有一些開源的db類庫,如adodb,pdo,pear:db,phplib,mdb等等。自己比較喜歡adodb。但是在zend framework中用的是pdo,只好又用起pdo了。感覺pdo也蠻好的。畢竟pdo是官方的。今天來說說pdo吧,我把他列在七種武器之首,長生劍,也顯出對這塊的偏愛,古代俠客都喜愛劍。兵器首選吧!
那pdo是什麼呢?先看看php manual怎麼介紹的,The PHP Data Objects (PDO) extension defines a lightweight, consistent interface for accessing databases in PHP.PHP6中將預設識用PDO連線資料庫,所有非PDO擴充套件將會在PHP6被從擴充套件中移除。該擴充套件提供PHP內建類 PDO來對資料庫進行訪問,不同資料庫使用相同的方法名,解決資料庫連線不統一的問題。
第一:安裝PDO
我這裡是WINDOWS下開發用的PDO擴充套件,php5.1以及以後版本的程式包裡已經帶了;php5.0.x則要到pecl.php.net下載,放到你的擴充套件庫,就是PHP所在的資料夾的ext資料夾下;
配置:
修改你的php.ini配置檔案,使它支援pdo.(以前在zend framework開發篇也介紹過的)。
把extension=php_pdo.dll前面的分號去掉,
往下還有
;extension=php_pdo.dll
;extension=php_pdo_firebird.dll
;extension=php_pdo_informix.dll
;extension=php_pdo_mssql.dll
;extension=php_pdo_mysql.dll
;extension=php_pdo_oci.dll
;extension=php_pdo_oci8.dll
;extension=php_pdo_odbc.dll
;extension=php_pdo_pgsql.dll
;extension=php_pdo_sqlite.dll
各擴充套件所對應的資料庫是:
Driver name Supported databases
PDO_DBLIB FreeTDS / Microsoft SQL Server / Sybase
PDO_FIREBIRD Firebird/Interbase 6
PDO_INFORMIX IBM Informix Dynamic Server
PDO_MYSQL MySQL 3.x/4.x
PDO_OCI Oracle Call Interface
PDO_ODBC ODBC v3 (IBM DB2, unixODBC and win32 ODBC)
PDO_PGSQL PostgreSQL
PDO_SQLITE SQLite 3 and SQLite 2
你要使用哪種資料庫,只要把相應的擴充套件前的註釋符號”;”去掉就可以了。
第二:使用PDO
pdo的類是這樣的。
class PDO {
__construct ( string $dsn [, string $username [, string $password [, array $driver_options ]]] )
bool beginTransaction ( void )
bool commit ( void )
string errorCode ( void )
array errorInfo ( void )
int exec ( string $statement )
mixed getAttribute ( int $attribute )
array getAvailableDrivers ( void )
string lastInsertId ([ string $name ] )
PDOStatement prepare ( string $statement [, array $driver_options ] )
PDOStatement query ( string $statement )
string quote ( string $string [, int $parameter_type ] )
bool rollBack ( void )
bool setAttribute ( int $attribute , mixed $value )
}
我們通過下面的例子來分析PDO連線資料庫,我用的是mysql。
<?php
$dbms='mysql'; //資料庫型別 Oracle 用ODI,對於開發者來說,使用不同的資料庫,只要改這個,不用記住那麼多的函數了
$host='localhost'; //資料庫主機名
$dbName='test'; //使用的資料庫
$user='root'; //資料庫連線使用者名稱
$pass=''; //對應的密碼
$dsn="$dbms:host=$host;dbname=$dbName";
//
try {
$db = new PDO($dsn, $user, $pass); //初始化一個PDO物件,就是建立了資料庫連線物件$db
echo "連線成功
“;
/*你還可以進行一次搜尋操作
foreach ($dbh->query(’SELECT * FROM user) as $row) {
print_r($row); //你可以用 echo($GLOBAL); 來看到這些值
}
*/
$db = null;
} catch (PDOException $e) {
die (”Error!: ” . $e->getMessage() . “
“);
}
//預設這個不是長連線,如果需要資料庫長連線,需要最後加一個引數:array(PDO::ATTR_PERSISTENT => true) 變成這樣:
$db = new PDO($dsn, $user, $pass, array(PDO::ATTR_PERSISTENT => true));
?>
查詢資料,上面我們已經進行了一次查詢,我們還可以使用如下的查詢:
<?php
$db->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER); //設定屬性
$rs = $db->query(”SELECT * FROM user”);
$rs->setFetchMode(PDO::FETCH_ASSOC);
$result_arr = $rs->fetchAll();
print_r($result_arr);
?>
以上因為用到setAttribute()方法,放上那兩個引數,把欄位名強制轉換成小寫。下面列出多有PDO::setAttribute()的引數:
PDO::ATTR_CASE: 強制列名變成一種格式,詳細如下(第二個引數):
PDO::CASE_LOWER: 強制列名是小寫.
PDO::CASE_NATURAL: 列名按照原始的方式
PDO::CASE_UPPER: 強制列名為大寫.
PDO::ATTR_ERRMODE: 錯誤提示.
PDO::ERRMODE_SILENT: 不顯示錯誤資訊,只顯示錯誤碼.
PDO::ERRMODE_WARNING: 顯示警告錯誤.
PDO::ERRMODE_EXCEPTION: 丟擲異常.
PDO::ATTR_ORACLE_NULLS (不僅僅是ORACLE有效,別的資料庫也有效): )指定資料庫返回的NULL值在php中對應的數值。
PDO::NULL_NATURAL: 不變.
PDO::NULL_EMPTY_STRING: Empty string is converted to NULL.
PDO::NULL_TO_STRING: NULL is converted to an empty string.
PDO::ATTR_STRINGIFY_FETCHES: Convert numeric values to strings when fetching. Requires bool.
PDO::ATTR_STATEMENT_CLASS: Set user-supplied statement class derived from PDOStatement. Cannot be used with persistent PDO instances. Requires array(string classname, array(mixed constructor_args)).
PDO::ATTR_AUTOCOMMIT (available in OCI, Firebird and MySQL): Whether to autocommit every single statement.
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY (available in MySQL): Use buffered queries.
例子中的$rs->setFetchMode(PDO::FETCH_ASSOC);是PDOStatement::setFetchMode(),對返回型別的宣告。
有如下:
PDO::FETCH_ASSOC — 關聯陣列形式
PDO::FETCH_NUM — 數字索引陣列形式
PDO::FETCH_BOTH — 兩者陣列形式都有,這是預設的
PDO::FETCH_OBJ — 按照物件的形式,類似於以前的 mysql_fetch_object()
插入,更新,刪除資料,
$db->exec(”DELETE FROM user where id=1″);
簡單的總結一下上面的操作:
查詢操作主要是PDO::query()、PDO::exec()、PDO::prepare()。
PDO::query()主要是用於有記錄結果返回的操作,特別是SELECT操作,
PDO::exec()主要是針對沒有結果集合返回的操作,比如INSERT、UPDATE、DELETE等操作,它返回的結果是當前操作影響的列數。
PDO::prepare()主要是預處理操作,需要通過$rs->execute()來執行預處理裡面的SQL語句,這個方法可以繫結引數,功能比較強大,不是本文能夠簡單說明白的,大家可以參考手冊和其他文件。
獲取結果集操作主要是:
PDOStatement::fetchColumn(),
PDOStatement::fetch(),
PDOStatement::fetchALL()。
PDOStatement::fetchColumn() 是獲取結果指定第一條記錄的某個欄位,預設是第一個欄位。
PDOStatement::fetch() 是用來獲取一條記錄,
PDOStatement::fetchAll()是獲取所有記錄集到一箇中,獲取結果可以通過PDOStatement::setFetchMode來設定需要結果集合的型別。
另外有兩個周邊的操作,一個是PDO::lastInsertId()和PDOStatement::rowCount()。PDO::lastInsertId()是返回上次插入操作,主鍵列型別是自增的最後的自增ID。
PDOStatement::rowCount()主要是用於PDO::query()和PDO::prepare()進行DELETE、INSERT、UPDATE操作影響的結果集,對PDO::exec()方法和SELECT操作無效。
事務和自動提交
至此,您已經通過 PDO 連線到了 mysql,在發出查詢之前,您應該理解 PDO 是如何管理事務的。如果之前沒有接觸過事務,那麼首先要知道事務的 4 個特徵:原子性(Atomicity)、一致性(Consistency)、獨立性(Isolation)和永續性(Durability),即 ACID。用外行人的話說,對於在一個事務中執行的任何工作,即使它是分階段執行的,也一定可以保證該工作會安全地應用於資料庫,並且在工作被提交時,不會受到來自其他連線的影響。事務性工作可以根據請求自動撤銷(假設您還沒有提交它),這使得指令碼中的錯誤處理變得更加容易。
事務通常是通過把一批更改積蓄起來、使之同時生效而實現的。這樣做的好處是可以大大提高這些更新的效率。換句話說,事務可以使指令碼更快,而且可能更健壯(不過需要正確地使用事務才能獲得這樣的好處)。
不幸的是,並不是每種資料庫都支援事務(Mysql5支援事務,mysql4我不知道),所以當第一次開啟連線時,PDO 需要在所謂的“自動提交(auto-commit)”模式下執行。自動提交模式意味著,如果資料庫支援事務,那麼您所執行的每一個查詢都有它自己的隱式事務,如果資料庫不支援事務,每個查詢就沒有這樣的事務。如果您需要一個事務,那麼必須使用 PDO::beginTransaction() 方法來啟動一個事務。如果底層驅動程式不支援事務,那麼將會丟擲一個 PDOException(無論錯誤處理設定是怎樣的:這總是一個嚴重錯誤狀態)。在一個事務中,可以使用 PDO::commit() 或 PDO::rollBack() 來結束該事務,這取決於事務中執行的程式碼是否成功。
當指令碼結束時,或者當一個連線即將被關閉時,如果有一個未完成的事務,那麼 PDO 將自動回滾該事務。這是一種安全措施,有助於避免在指令碼非正常結束時出現不一致的情況 —— 如果沒有顯式地提交事務,那麼假設有某個地方會出現不一致,所以要執行回滾,以保證資料的安全性。
try {
$db = new PDO(’mysql:host=localhost,dbname=test’, ‘toot’, ‘123456′,
array(PDO_ATTR_PERSISTENT => true));
echo “Connected/n”;
$db->setAttribute(PDO_ATTR_ERRMODE, PDO_ERRMODE_EXCEPTION);
$db->beginTransaction();
$db->exec(”insert into user(id, name, pwd) values (1, ‘Joe’, ‘123456′)”);
$db->exec(”insert into userDetail(uid, add, tel)
values (1, ‘上海新閘路’, ‘15555555555′)”);
$db->commit();
} catch (Exception $e) {
$dbh->rollBack();
echo “Failed: ” . $e->getMessage();
}
在上面的示例中,假設我們為一個新使用者建立一組條目,這個使用者有一個 ID 號,即 1。除了輸入這個人的基本資料外,我們還需要記錄使用者的詳細資訊。兩個更新分別完成起來很簡單,但通過將這兩個更新包括在 beginTransaction() 和 commit() 呼叫中,就可以保證在更改完成之前,其他人無法看到更改。如果發生了錯誤,catch 塊可以回滾事務開始以來發生的所有更改,並打印出一條錯誤訊息。
並不是一定要在事務中作出更新。您也可以發出複雜的查詢來提取資料,還可以使用那種資訊構建更多的更新和查詢。當事務在活動時,可以保證其他人在工作進行當中無法作出更改。事實上,這不是 100% 的正確,但如果您之前沒有聽說過事務的話,這樣介紹也未嘗不可。
預處理語句和儲存過程
很多更成熟的資料庫都支援預處理語句的概念。什麼是預處理語句?您可以把預處理語句看作您想要執行的 SQL 的一種編譯過的模板,它可以使用變數引數進行定製。預處理語句可以帶來兩大好處:
查詢只需解析(或準備)一次,但是可以用相同或不同的引數執行多次。當查詢準備好後,資料庫將分析、編譯和優化執行該查詢的計劃。對於複雜的查詢,這個過程要花比較長的時間,如果您需要以不同引數多次重複相同的查詢,那麼該過程將大大降低應用程式的速度。通過使用預處理語句,可以避免重複分析/編譯/優化週期。簡言之,預處理語句使用更少的資源,因而執行得更快。
提供給預處理語句的引數不需要用引號括起來,驅動程式會處理這些。如果應用程式獨佔地使用預處理語句,那麼可以確保沒有 SQL 入侵發生。(然而,如果您仍然將查詢的其他部分建立在不受信任的輸入之上,那麼就仍然存在風險)。
預處理語句是如此有用,以致 PDO 實際上打破了在目標 4 中設下的規則:如果驅動程式不支援預處理語句,那麼 PDO 將模擬預處理語句。
<?php
$sql = 'SELECT name, colour, calories
FROM fruit
WHERE calories < :calories AND colour = :colour';
$sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(’:calories’ => 150, ‘:colour’ => ‘red’));
$red = $sth->fetchAll();
$sth->execute(array(’calories’ => 175, ‘colour’ => ‘yellow’));
$yellow = $sth->fetchAll();
?>
還有一個列子
<?php
$sth = $dbh->prepare(’SELECT name, colour, calories
FROM fruit
WHERE calories < ? AND colour = ?');
$sth->execute(array(150, ‘red’));
$red = $sth->fetchAll();
$sth->execute(array(175, ‘yellow’));
$yellow = $sth->fetchAll();
?>
此外pdo還有兩個回饋錯誤函式,errorCode();errorInfo().