Andi Gutmans看 PHP 5、Oracle 的未來

日期:2006-09-21  作者:喜騰小二  來源:PHPChina


PHP 5 的發佈經理對 PHP 5 一些新特性的概述及對其未來(對 Oracle 使用者而言)的評述。

PHP 5(PHP:超文字預處理語言版本 5)於 2004 年 7 月 13 日正式發佈。毫不奇怪,由於 PHP 在 Web 應用程式市場中的領先地位,因此該版本獲得了媒體的廣泛報道。.NET 和 J2EE 等技術確實在曝光率和宣傳報道方麵超過 PHP,但易用性、高效能、與 Apache Web 伺服器的緊密整合以及大量應用程式建置塊使 PHP 成為領先的 Web 應用程式開發語言之一。

您可能會問自己,既然提供了 Zend Engine 功能的 PHP 4 已經如此成功,為什麼還需要 PHP 5 和 Zend Engine II 呢?事實是,PHP 4 在某些方麵並不擅長。這些方麵中的大多數對於大型項目和公司(項目管理的結構化程度更高,且係統之間必須俱備協同工作的能力)而言更為重要。PHP 5 解決了這些問題,使 PHP 不但對此類項目更俱吸引力,而且還仍是 Web 應用程式開發的領先技術。

在本文中,我將介紹:

  • PHP 5 的幕後知識
  • 它的某些新特性的簡短概述
  • 簡要展望 PHP 和 Oracle 使用者的未來。

Zend Engine II 新的麵嚮物件的模型

背景隨着 PHP 使用範圍的穩步增長,它在較大項目中的使用率也在不斷上升。大型項目好像都使用麵嚮物件 (OO) 的方法。並不是說您不能編寫小型 OO 應用程式,而且即便不使用麵嚮物件的編程 (OOP) 方法也完全可以編寫令人印象深刻的大型應用程式。但人們往往在這些情況下選擇 OO 範例 — 可能是因為 OOP 為功能和技術設計提供更多慣用的工俱(UML — 統一建模語言)、為重複出現的問題提供重用解決方案(設計模式)以及 OO 語言本身的內建機制(說明強化軟體設計和合同)。

PHP 先前版本中的物件模型存在的主要問題是,將物件實現為俱有與整數和字串相似的副本語意的自帶類型。這不但會因為 PHP 有時進行的意外隱式物件克隆而導緻的某種非常令人混淆的行為,而且使我們無法實現某些基本功能,如取消對方法返回物件的引用的功能。

以下範例演示了這兩個問題。
a) 隱式物件克隆:


class Person {
var $name;

function Person($name) {
$this->name = $name;
}

function setName($name) {
$this->name = $name;
}

function getName() {
return $this->name;
}
}

function lowerCaseName($obj)
{
$new_name = strtolower($obj->getName());
$obj->setName($new_name);
}

$obj = new Person("Andi");
lowerCaseName($obj);
print $obj->getName();

?>

大多數開發人員認為此範例會列印出“andi”。但令人吃驚的是,此範例在 PHP 4 中卻列印出“Andi”。這是因為正如前麵提到的,PHP 4 將物件作為常規自帶類型處理,所以將 $obj 按值傳遞給 lowerCaseName() 實際是克隆該物件。lowerCaseName()$obj 執行的最終操作在該物件的克隆版本上進行。此行為不但導緻令人吃驚的結果,而且對於認識到此問題的開發人員而言,它將需要按引用傳遞和返回物件,由於開發人員必須在許多位置插入“&”(按引用傳遞、按引用返回和按引用賦值),因此將使程式碼的維護更加困難。

b) 無法取消對方法返回物件的引用:

$obj->getParentObject()->method();

如果您不熟悉 PHP 4,則可能認為此範例可以正常執行。但由於前麵提到的隱式克隆問題,因此不俱有取消對方法返回物件的引用的功能,從而無法實現這一功能。作為變通方法,很多 PHP 4 程式碼將如下所示:

$temp_obj &= $obj->getParentObject();
$temp_obj->method();

還有更多範例可以幫助物件的基本結構如何在 PHP 4 變得存在缺陷,但這兩個範例足以讓您認識到這一點。

主要的新語言特性。PHP 5 中最基本、最重要的變化是使用了物件句柄(或 Id),而不是將其實現為自帶資料類型。複製時實際上隻複製句柄(Id 編號)本身;並不複製這些句柄所代表的物件。該語言在語義方麵看似較小的這個變化卻是催生 PHP 5 大多數新特性的主要動力。它允許新增新的語言特性和新的 PHP 延伸,如完全利用新語義的很棒的 SimpleXML。

下麵列出了 PHP 5 中的新語言特性,但本文不對其進行詳細介紹(否則本文就成一本書了)。

新的物件克隆語義 正如所指出的,無論是物件賦值、按值傳遞物件,還是從函式中按值返回物件,指令檔引擎均不會自動克隆 PHP 5 中的物件。如果需要克隆,則開發人員可以透過使用新的 clone 關鍵字(例如,clone $obj;)顯式克隆物件。開發人員還可以在類中實現一個名為 __clone() 的方法,當克隆操作複製了所有原始物件的內容後,將在得到的新物件中調用此方法。實現此回呼不是必需的,但如果開發人員希望每個物件自身擁有特定資源的一個副本(以便為客隆物件建立該資源的一個新版本,否則,這兩個物件將使用相同的資源),則實現此回呼很有用。此類資源的一個實例就是檔案。

公共/私有/受保護的訪問修飾符。PHP 5 支援其他麵嚮物件的語言(如 C++ 和 Java)中通常都俱有的 PPP(公共/私有/受保護的)訪問修飾符。可以將這些訪問修飾符用於內容和方法,以施加訪問限制。

介麵、抽象類和方法。我們在 Zend Technologies 收到許多要求在 PHP 5 中提供多重繼承 (MI) 的請求,因此我們決定在 PHP 5 中解決此問題。在比較了許多語言(主要是 C++ 和 Java)的實現,瞭解了哪種語言最容易適應 PHP 的動態本質後,我們決定使用 Java 樣式的介麵和抽象類為 MI 提供一個解決方案。

允許 PHP 延伸多載 PHP 物件語法。PHP 5 最重要的特性之一可能就是 Zend Engine II 在物件語法和其語義之間存在一個抽象層。此方法允許 PHP 延伸建立它們自己的物件,這些物件的行為與使用者級 PHP 物件的行為不同。例如,新的 COM 延伸使用這些多載功能,以便使用常規 PHP 物件語法以一種對 PHP 開發人員而言比較自然的方式訪問 COM 物件:

$ie = new COM("InternetExplorer.Application");
$ie->Visible = true;
$ie->Navigate("http://www.php.net/");

其他利用此功能的延伸包括 SimpleXML、SOAP 和 Perl 延伸。

其他新特性 PHP 5 中大概有 12 個以上的新語言特性,如類常量、靜態內容和方法、__autoload() 以及 instanceof 運算元。您可以在 http://www.zend.com/php5 中找到一個更完整的清單。

設計模式 正如前麵所討論的,能夠在大型(通常也可以是小型)PHP 軟體項目中使用設計模式非常重要。雖然可以在 PHP 4 中利用此類模式,但由於缺少重要的語言特性(如靜態內容和方法、PPP 訪問修飾符和介麵,因此通常很難推行這些模式的所有語義。

單實例模式 經常使用並且非常出色的是單實例模式。儘管它是一個比較簡單的模式,但要完整地實現它,必須使用靜態內容和方法以及 PPP 訪問修飾符。

例如:


class MySingleton {
static private $instance = NULL;

private function __construct() {
}

private function __clone() {
}

static public function Instance() {
if (self::$instance == NULL) {
self::$instance = new MySingleton();
}
return self::$instance;
}
// ... Additional code for the MySingleton class.
}

此實現利用了 PHP 5 新特性,從而獲得了一個比較整潔並且不易出錯的單實例實現。例如,將構造函式和客隆方法宣告為 private 的功能可以防止開發人員不小心多實例化一個 MySingleton 類的副本,這是因為隻有該類自己才可以訪問這些方法。使用靜態內容支援是為了實現一個可以全域訪問的內容 (self::$instance),該內容引用類的單一實例。將內容宣告為 private 可以確保隻有該類自己才可以使用該內容。

不可變物件模式 另一個不太常用的設計模式是不可變物件模式。此模式通常用於對相對較少的值進行大量引用的應用程式。它允許透過使物件不可變(禁止其狀態變化)並強制實現此目的程式碼建立類的一個新實例來使應用程式程式碼共用物件。

以下範例演示了如何建立一個表示 SQL 查詢的類。該組合的查詢陳述式本身可能用在應用程式的多個位置。要變更該查詢的值的程式碼可以使用 changeStmt() 方法實現此目的,該方法返回代表指定查詢字串的新物件的句柄。


final class ImmutableQueryStatement {
private $stmt;

public function __construct($stmt) {
$this->stmt = $stmt;
}

public function getStmt() {
return $this->stmt;
}

public function changeStmt($stmt) {
return new ImmutableQueryStatement($stmt);
}
}

此範例利用了幾個 PHP 5 新語言特性。首先,它使用 final 關鍵字,以使該類不會再有“子類”。該方法使開發人員不能再繼承和實現可變類。此外,changeStmt() 利用新物件句柄並按值返回開啓新檔的物件(在 PHP 4 中,必須按引用返回新物件實例,從而使實現復雜化)。最後(但不是最次要的),與上一個範例相似,訪問修飾符用於指定該類應遵守的訪問合同。

PHP 5 中的 XML 和 Web 服務

背景 在過去的幾年裡,XML 變得越來越重要,它允許不同的應用程式和係統使用標準工俱和方法協同處理資料。這是 Oracle 及其他供應商堅定不移地支援和采用該技術的原因之一。在每個公司中,資料都是組織的核心部分。

PHP 4 中的 XML 支援非常混亂。儘管它支援 SAX(用於 XML 的簡單 API)、DOM(文檔物件模型)和 XSL(可延伸樣式表語言),但卻沒有統一、符合標準的實現。SAX 實現基於逐漸過時的 Expat XML 分析器,DOM 延伸的命名慣例不符合標準,並且該延伸仍處於試驗狀態。此外,對 XSL 的支援還要使用稱為 Sablotron 的 XML 庫。

因此決定在 PHP 5 中重新編寫 XML 支援。來自 PHP 社區的幾位開發人員將此工作變為了現實。第一個也是最重要的決定是所有 XML 功能將基於 Gnome 項目優秀的 libxml2 庫。依照此原則,重新編寫了現有的三個延伸。最重要的是,修改了 DOM 延伸並將其介麵重新設計為符合 W3C。當 PHP 5 發佈時,DOM 已脫離了試驗階段,變得功能完備且穩定。

SimpleXML 除了對現有的 XML 延伸進行重要的重新編寫和統一以外,還出現了一個新的 XML 延伸。此副檔名為 SimpleXML,它允許開發人員能像訪問自帶 PHP 物件那樣訪問 XML 檔案。回顧本文的前幾個部分,這之所以成為可能是因為新的 Zend Engine II 使延伸能夠多載麵嚮物件的語法。

考慮以下 XML 檔案:



John Doe
87234838


Janet Smith
72384329


以下 PHP 5 程式碼叠代 XML 檔案,列印客戶的名稱和帳號:


$clients = simplexml_load_file('clients.xml');

foreach($clients->client as $client) {
print "$client->name account:$client->account_number
";
}

執行此範例指令檔將獲得以下輸出:

John Doe account: 87234838
Janet Smith account: 72384329

有了 SimpleXML,訪問 XML 檔案變得非常容易。我相信,SimpleXML 將使 PHP 開發人員在處理 XML 檔案時獲得革命性的易用性。如果 SimpleXML 無法執行某些操作,則由於 SimpleXML 和 DOM 延伸都使用同一基礎庫,因此可以將 SimpleXML 物件轉換為 DOM 樹,在 DOM 中可以執行更進階的 XML 操作。SimpleXML 與 DOM 之間的這種相互轉換是零複製的,也就是它既不花費時間也不占用額外的記憶體。

SOAP 回顧前麵的介紹,我曾將互操作性看作是大公司的主要問題。使用 Web 服務(更俱體地說是 SOAP 協定)解決兩個或更多係統之間的互操作性問題已變得越來越普遍。

由於 PHP 4 的預設發行套件未提供自帶整合的 SOAP 支援,因此我們認為在 PHP 5 中必須解決此問題。因此,我們為 SOAP(用戶端以及伺服器 API)建立了一個新的自帶實現,它允許 PHP 開發人員輕鬆建立和使用 Web 服務。

以下範例演示了從 PHP 中調用 SOAP 服務是何等簡單。您可能注意到,此延伸使用了與前麵相同的麵嚮物件的多載功能。


$client =
new SoapClient("http://services.xmethods.net/soap/urn:xmethods-delayed-quotes.wsdl");

print($client->getQuote("ORCL"));

編寫本文檔時,執行此範例將列印 11.23

未來和 Oracle

總論 2004 年 7 月發佈的 PHP 5 誕生時間很短。儘管如此,在 PHP 發展過程中卻發生了很多令人關注的事情。在改進指令檔引擎的效能方麵已經做了大量的工作,而對 Oracle 讀者而言,最重要的是有很多與資料庫相關的新革新措施。在 PHP 社區中,Oracle 的使用範圍很廣,很多 Zend 客戶都是 Oracle 使用者。他們使用 Oracle 的方式雖然與其他資料庫有所不同,但通常都是一個非常明智的選擇,這與 Oracle 的公認跟蹤記錄、進階特性,以及(往往)Oracle 基礎架構中的現有投資相關。

指令檔引擎效能 開發 PHP 5 時,Zend 和社區更專注於功能而不是效能。因此,除了幾個個別情況以外,PHP 4 與 PHP 5 的指令檔引擎效能差別並不大。

在大多數 PHP 應用程式中,PHP 的原始執行效能不是主要瓶頸。最常見的瓶頸與 I/O 相關,並通常與資料庫相關。儘管如此,我們仍相信改進指令檔引擎本身的效能將肯定為 PHP 使用者帶來好處。因此,我們決定投入大量資源來改進 PHP 5.1.x 的效能。

自從 PHP 5 發佈以來,我們投入了大量資源來調整指令檔引擎。許多構思都出自由 Thies Arntzen 和 Sterling Hughes 在大約一年前發佈的效能補丁。其他構思出自 Zend 和 PHP 開發人員社區的內部。最終我們設計出一種引擎,它在綜合基準測試(不包括 I/O 和實際程式碼的基準測試)中的速度通常為 PHP 4.0 和 PHP 5.0 的兩倍以上。

改進非常引人注目,並且當 PHP 5.1.0 發佈時,所有 PHP 使用者都可以使用它,而不必對他們的源程式碼進行任何變更。我認為,PHP 5.1.0 將在 2005 年第一個季度之初發佈,但對於開放源項目來說,誰也不敢保證。

SQL Relay。SQL Relay(是一個非常有趣的協力廠商項目。它是一個為 SQL 連線(包括 Oracle)實現代理中介的項目,允許使用 PHP 實現資料庫連線池。

該項目提供了它自己的 PHP 資料庫延伸(您必須變更您的 PHP 資料庫程式碼)。此延伸與 SQL Relay 中介通信,後者在延伸與資料庫之間傳遞查詢和結果。

SQL Relay 的某些優點:

  • 使用連線池,您可以限制開啟的資料庫連線數。
  • 在 PHP 持久連線無法用在您環境的情形,此解決方案可以解決初始化 Oracle 資料庫連線時連線時間較長這一問題。
  • 該項目還支援其他編程語言。如果您使用的是一個混合環境,則可以利用從 PHP 中使用的同一個 SQL Relay 後臺程式。除 PHP 以外,還支援 C、Java、Perl 以及許多其他語言。
  • 啓動和執行 SQL Relay 非常簡單。我還要指出,SQL Relay 作者對我的問題的反應非常積極。

SQL Relay 的某些缺點:

  • 必須使用一個不同於 PHP Oracle 延伸的 API。
  • 結果集被複製兩次:首先複製到 SQL Relay 中介,然後複製到 PHP。
  • 沒有哪個 API 像 PHP 自帶的 oci8 延伸一樣功能豐富。

我認為,如果您的項目確實需要 Oracle 資料庫連線池,則您最好試一試 SQL Relay。它可能並不盡善盡美,但在一個更好的解決方案推出之前可能需要一段時間,且此解決方案確實有效。

PDO 除了現有的 oci8 PHP 延伸(俱有一個自帶的 Oracle 資料庫介麵)以外,PHP 社區還一直緻力於開發一個新的資料庫抽象層。由於 Oracle 技術網已經提供了一篇深入介紹 PHP 資料物件 (PDO) 的文章(作者 Wez Furlong),因此我們完全可以認為 PDO 值得期待。PHP 在很長時間以來一直期待一個好的自帶資料庫抽象。我認為,PDO 就是我們一直期待的解決方案。PDO 的設計者是 PHP 社區的一些高水平的開發人員,我很喜歡他們開發 PDO 的方法。以下是他們的設計目的清單(已寫入 PDO README 檔案中:

  1. 是輕型的。
  2. 為常見的資料庫操作提供通用 API。
  3. 效能很高。
  4. 將大多數 PHP 特定程式碼置於 PDO 內核(如持續性資源管理)中;驅動程式隻應關注如何獲取資料而不是 PHP 的內部結構。

一方麵,它為使用資料庫提供通用 API。但它還允許每個驅動程式新增自己的附加功能,因此 PDO 不但支援最常見的資料庫 API,而且還使您能夠使用資料庫提供的所有特性。我們都知道 Oracle 提供了很多特性。

PropelPropel 是一個物件持久性和查詢框架。它采用物件/關係對應 (ORM) 模型並基於 Apache Torque 項目,該項目對於 Java 執行相同操作。與 PDO 不同,Propel 是一個非常進階的資料庫抽象層,它重新定義了您查詢、建立和操作持久性物件的方式。正如對 OO/RDBMS 對應係統所期望的,Propel 還處理資料庫模式建立。

此類係統有很多優點。對於新手,開發人員可以集中大部分時間編寫業務邏輯,並且不必處理資料庫的復雜性 — 無論是模式管理還是編寫精緻的 SQL 陳述式。資料庫操作非常自然,這是因為開發人員隻使用常規物件,而持久層處理更新資料庫中相應欄位和行的低級細節。

缺點是您失去了某些控制。OO 模型到關係資料庫的自動對應並非總是很順利。它不但使得手動編寫精緻、強大的查詢很困難,而且也不允許您這樣做 — 您破壞了抽象,並且微小的對應更新就可能破壞應用程式。因此,使用這樣的係統意味着您必須遵守工俱的規則。在大多數情況下,這樣的代價是可以接受的,這是因為提高的生產率有助於縮短開發時間並提高程式碼質量。但在某些情況下,您可能絕對需要這樣的控制。

Propel 是一個非常有趣的項目,一定會派上用場。此外,它是基於名為 Creole 的資料庫抽象層建置的。與 PDO 不同,此抽象層嘗試盡可能地模仿 JDBC,並且在您將現有 Java 程式碼轉換為 PHP 的情況下更易於使用。也就是說,如果 PDO 成為主流並作為標準 PHP 的一部分發行,那麼最好遵守它。

Java 整合 一年前,Zend 和 Sun Microsystems 啓動了 Java 規範請求 (JSR) 223,用以定義 PHP 和 Java 的介麵標準。如今,JSR 的專家組由許多軟體供應商(包括 Oracle)組成。儘管 JSR 提到了所有指令檔語言,但最初的興趣卻在於 PHP 以及主要是看能否從 PHP 中調用 Java 程式碼。您可以猜測此類連線的主要動機之一是將前端 PHP 伺服器連線到後端 J2EE 應用伺服器,更俱體地說,是能夠從 PHP 程式碼直接調用 Enterprise Java Bean (EJB)。

以下是使用 Java 介麵實現的 Oracle JDBC 查詢範例:

圖 1:連線 PHP 和 Java:Oracle JDBC 查詢

您可以看到您將可以在 PHP 中編寫 Java 程式碼。這會使您能夠調用您可能擁有的任何 Java 業務邏輯(特別是 EJB)。

此連線支援為已經投資了後端業務邏輯但希望利用 PHP 的快速開發時間和特性的 Oracle 應用伺服器使用者提供了新的可能性。

結論

PHP 5 無疑是 PHP 和 PHP 社區的重大進步。在 O'Reilly 開放源程式碼會議上,一位記者詢問某些 PHP 社區領導者:PHP 5 是否是我們翹首期望的一切?回答是一緻的;PHP 5 遠遠超過了我們最初的計劃和期望。

更俱體地說,我認為 Oracle 使用者有很多值得期望的事情。就 Oracle 發佈的有關在未來的 Oracle 應用伺服器版本中包含 PHP 的發展方嚮宣告而言,顯而易見,公司已經認識到了 PHP 技術的重要性。我相信,在認識到 PHP 技術的重要性之後將出現各種提高 Oracle/PHP 生產率和靈活性(兩者在如今不斷變化的市場上的需求程度很高)的解決方案。即將推出的 Oracle 10g 版本中的初始 PHP 繫結以及用於 Oracle JDeveloper 的 PHP 延伸是 Oracle 支援廣泛流行的 PHP 的重要先期步驟。


Andi Gutmans 是 Zend Technologies 的創辦人和副總裁。1997 年之後,他一直緻力於開發 PHP,並與 Zeev Suraski 攜手,先後建立了 PHP 3 和 PHP 4。最近,Andi 為即將推出的 PHP 5 版本領導了 Zend Engine II 的麵嚮物件的改進,並參與編寫了 PHP 5 強大編程 (Prentice Hall) 一書。歡迎您將有關 PHP 5 的建議發送到 andi@zend.com

<<<返回技術中心

技術文章

站內新聞

我要啦免费统计