使用 Phalanger 整合 PHP 和 .Net

03ngnntds發表於2019-04-01

Phalanger 是一種 PHP 語言編譯器,也是針對 .NET 的 PHP 執行時。 它可以用於把 PHP web 專案編譯成 .NET 位元組碼,並在 Windows 中使用 IIS 或者在 Linux 上使用 Mono 和 Apache 作為   應用程式來執行。 然而,Phalanger 不僅僅是把已經存在的 PHP 應用編譯到 .NET 中。

我們可以使用 Phalanger 建立組合 .NET 和 PHP 的解決方案,所採用的方式用標準的 PHP 直譯器是不可能做到的。 有了 Phalanger 擴充套件,PHP 程式可以直接使用 .NET 類,而 .NET 程式(比方說用 C# 編寫的)也可以動態地呼叫 PHP 指令碼,或者使用在 PHP 中實現的函式和類【6】。

本文中,我麼會簡要地介紹 Phalanger,然後檢視三種使用方案。 我們會討論如何整合 PHP 應用程式和 .NET;如何高效地在 Windows 上執行 PHP 應用程式,以及如何使用 PHP 作為   的檢視引擎(view engine)。

Phalanger 簡介

Phalanger 已經存在一段時間了。 第一版 Phalanger 是於 2003 年在布拉格的查爾斯大學作為軟體專案建立的。稍後就開始了2.0版本的開發,並且於 2006 年在 CodePlex 作為開源專案釋出。 微軟支援了這個專案一段時間,後來一位 Phalanger 開發者加入微軟,並從事動態語言執行時方面的工作。

Phalanger 相關活動在 2008 年恢復,這多虧有了與 Jadu 的合作,它使用 Phalanger 為在 PHP 中開發的 CMS 構建了 .NET 版本。 從 2010 年開始,Phalanger 的開發主要由 DEVSENSE 提供資金支援,它也為 Phalanger 提供了商業支援。 最近釋出的版本 Phalanger 2.1【7】,其中提升了與標準 PHP 實現的相容性,在動態操作的實現過程中利用了 DLR,並提供了 PHP 和其他 .NET 語言(像C#、F#和 Visual Basic)之間的互操作性。

Phalanger 的元件

Phalanger 包括多個部分獨立的元件,可以用來開發執行在 .NET 上的 PHP 應用程式,並使用 .NET 或 Mono 來執行它們:

Phalanger 編譯器Phalanger 會把 PHP 原始碼編譯成 .NET 程式集,它可以使用 .NET JIT(Just-in-time 編譯器,它會為當前平臺生成原生程式碼)執行。 編譯後的 PHP 程式碼會使用 Phalanger 執行時和動態語言執行時,從而提供了 PHP 語言動態特性的高效率實現。
Phalanger 執行時和類庫Phalanger 執行時提供了對陣列之類 PHP 特性的實現。 Phalanger 還包含了針對I/O、正規表示式以及其他標準 PHP 類庫的 .NET 實現。
本地擴充套件在 32 位 Windows 平臺上,Phalanger 可以透過本地的橋接程式使用所有現存的 PHP 4 擴充套件。 儘管這會帶來一些執行時負載,但這讓我們不需要額外工作就可以執行某些 PHP 應用程式。
託管的擴充套件 透過包裝 .NET 中提供的類似功能,PHP 擴充套件也可以重新實現。 這些擴充套件可以是由任何 .NET 語言編寫,並提供很好的效能。 Phalanger 中包含多個擴充套件,包括 SPL、JSON、SimpleXML、MySQL 和 MS SQL 的提供程式。 DEVSENSE【9】還提供了附加的擴充套件,像 Memcached、影像和 cURL 等。
與 Visual Studio 的整合Phalanger 還與 Visual Studio 整合(最近的更新支援 Visual Studio 2010)。 整合功能新增了針對 PHP 檔案的顏色突出顯示和智慧提示功能,讓我們可以除錯使用 Phalanger 執行的 PHP 應用程式。
Phalanger 使用案例

Phalanger 在很大程度上與 PHP 5 相容,可以執行大量開源的 PHP 專案,包括 WordPress 和 MediaWiki。 我們可以使用它把這些專案整合到 .NET 生態系統中,也可以開發新的專案,它會兼有 PHP 和 .NET 的優勢。 在本文剩下的內容中,我們會討論以下三種使用案例:

方案1: 高效執行 PHP 應用程式。 使用 PHalanger 在 Windows 上編譯的 PHP 應用程式的效能,要比透過 FastCGI 使用標準 PHP 直譯器執行的高。 這使得選擇 Phalanger 在 Windows 環境中部署 PHP 很具有吸引力。
方案2: 把 WordPress 與   整合。 使用 Phalanger 編譯的 PHP 程式碼能夠呼叫所有 .NET 程式庫。 這可以用於在 PHP 和   應用程式之間共享使用者資料庫或者其他資料。
方案3: 從   應用程式中呼叫 PHP。 PHP 的靈活性對於編寫指令碼或者編寫 web 應用程式的表現層非常有用。 有了 Phalanger,我們就可以在 .NET 中開發應用程式,並使用 PHP 作為指令碼語言或者檢視引擎。
以下三個部分會詳細討論各種方案。 我們首先會給出概覽,然後檢視一些技術細節,它會說明 Phalanger 中讓你感興趣的內容。

方案1: 高效執行 PHP 應用程式

Phalanger 之所以能夠高效地執行 PHP 應用程式,是因為以下兩個原因。 首先,它會編譯 PHP 原始碼,而不是解釋它;其次,它會把應用作為   應用程式執行,那會在 Windows 下提供額外的效能優勢。

使用 Phalanger 和 .NET 編譯 PHP

編譯過程如圖 1 所示。正如圖上所顯示的,Phalanger 會把 PHP 原始碼編譯成 .NET IL(中間語言),那是與架構獨立的低階位元組碼。 編譯後的程式碼會使用 PHP 核心庫(Phalanger 的一部分)和動態語言執行時(DLR)來執行標準的 PHP 操作。 當應用程式啟動時,.NET JIT(just-in-time)編譯器會把這些元件轉換為針對當前處理器架構最佳化過的原生程式碼。

圖1. 使用 Phalanger 把 PHP 原始碼編譯成原生程式碼的過程

正如 Phalanger 評測顯示【10】,使用 Phalanger 編譯的 WordPress 在 Windows 下的效能比透過 FashCGI 使用標準 PHP 直譯器的好,也比透過 WinCache 使用 PHP 的稍好一些。 然而,評測沒有測試 Phalanger 最新的版本,它使用 DLR 進行了進一步最佳化。

使用   部署 PHP 應用程式

Phalanger 應用程式的執行方式和   應用程式完全相同。 這讓它具有了重要的效能優勢,特別是在 Windows 系統下,程式要比執行緒耗費更多資源。

圖 2 顯示了執行 PHP 應用程式的不同可選方案。

當使用標準 CGI 模式時,web 伺服器會為每個進入的請求啟動新的程式。 在 Windows 下,這樣做的效率不高,它還阻止了共享位於共享記憶體中的狀態,也很難進行程式中快取(in-process caching)。 當使用 FashCGI 模式時,web 伺服器會重用程式,這樣它不需要為每個請求啟動新的程式。 然而,這還是無法共享記憶體中的狀態,因為不同的程式擁有不同的狀態。

圖2. 使用 CGI、FashCGI 和 Phalanger 執行 PHP

Phalanger 的行為方式和所有   應用一樣。 單獨的叫做應用池(Application Pool)的   程式會處理所有進入的請求。 我們甚至可以在單一程式(應用池)中配置多個 PHP 應用程式(像多個 WordPress 的獨立例項)。 在程式中,會有多個執行緒,這些執行緒會被重用以處理單獨的請求。 在 Windows 下,執行緒要比過程更輕量級,所以這種解決方案更有效率,並且會消耗更少的記憶體。

對於執行在單一程式中的應用程式,我們可以進行進一步的最佳化,並採用其它有趣的方案。 例如,Phalanger 會使用動態語言執行時(DLR)來做動態方法呼叫。 DLR 會使用與時間相適應的快取機制,因此在幾次請求之後,DLR 就會“知道”應用程式使用的是哪個方法,並變得更快一些。 這隻有在單一程式中處理請求的情況下才可能做到。

在單一程式中執行所有程式碼也意味著應用程式可以在記憶體中儲存全域性狀態。 這可以用於實現與 WinCache 提供的 User Cache 類似的功能,但是不會有跨程式通訊造成的負載。

方案2: 把 WordPress 與   整合

PHP 的一點優勢就在於擁有大量優秀的開源 CMS 系統(WordPress、Joomla 等等)、表單應用程式(phpBB 及其他)和 wiki(Mediawiki 及其他),其中很多都透過了 Phalanger 的測試。

這些應用通常會比 .NET 平臺下類似的程式包提供更多特性。 開發基於   網頁的公司可能會面臨以下情況:

它需要向現存的   解決方案中新增 wiki、論壇或者部落格,但是隻有在 PHP 中存在合適的應用程式(例如,免費並且帶有所有必要特性)。
應用程式可能會在子域下執行,但是它應該共享使用者資料庫。 此外,一旦使用者登入到主頁,那麼他就應該同時登入到 wiki、論壇和部落格上。
 應用程式可以使用   的成員管理(  Membership),它還用來管理使用者、角色和功能的標準機制。 有了 Phalanger,我們就可以修改開源的 PHP 專案,從而使用同樣的機制。 下一部分會演示使用 WordPress 如何做到這一點。

為 WordPress 實現   成員管理外掛

如果你對程式碼不感興趣,那麼就可以略過這個部分,直接檢視第三種情況。 但是,我們不會檢視技術細節,只是對讓 PHP 呼叫 .NET 程式庫的 PHP 擴充套件做簡要的概述。

我們可以使用外掛輕鬆地自定義在 WordPress 管理使用者的方式。 管理使用者的外掛需要實現一個 PHP 類,其中有各種成員函式。 其中最值得期待的功能就是身份驗證,它會獲得使用者名稱和密碼。 它應該填充當前使用者的資訊,或者,當使用者不存在的時候,就會把名稱設定為 NULL。

為了使用 .NET 中的   成員管理來實現身份驗證功能,我們可以使用 System.Web.Security 名稱空間中的功能。 靜態方法 Membership.ValidateUser 會檢查密碼是否正確,而 Membership.GetUser 會返回使用者的基本資訊。 使用 Phalanger,我們可以訪問 .NET 物件,就像它是標準的 PHP 物件一樣,這樣實現驗證機制就很簡單了。 程式碼 1 展示了簡化後的程式碼。

程式碼 1 在 WordPress 外掛中實現身份驗證功能的函式

import namespace System:::Web:::Security;
function authenticate (& u s e r n a m e , username, u s e r n a m e , password) {

global $errors;

// Test whether the password is correct

if (Membership::ValidateUser ( u s e r n a m e , username, u s e r n a m e , password)) {

// Get information about the user and fill $userarray

u s e r = M e m b e r s h i p : : G e t U s e r ( user = Membership::GetUser ( u s e r = M e m b e r s h i p : : G e t U s e r ( username);

$userarray[‘user_login’] = $user->UserName;

$userarray[‘user_email’] = $user->Email;

$userarray[‘display_name’] = $username;

$userarray[‘user_pass’] = $password;

// Loading of roles & profiles omitted for simplicity

// Update or create the user information in WordPress

if ( i d = u s e r n a m e e x i s t s ( id = username_exists ( i d = u s e r n a m e e x i s t s ( username)) {

$userarray[‘ID’] = $id;

wp_update_user ($userarray);

}

else

wp_insert_user ($userarray);

} else {

// Report error if the login failed

$errors->add (‘user-rejected’, ‘Log-in failed!’);

$username = NULL;

}

}

程式碼首先宣告瞭重要的名稱空間。 這是一個非標準的 Phalanger 擴充套件,它從引用的程式庫的 .NET 名稱空間中匯入了功能(我們可以使用 web.config 檔案來引用程式庫)。 在將來的版本中,Phalanger 會使用 PHP 5.3 支援的標準名稱空間,但是這項改變還沒有完全實現。

剩餘部分的程式碼看起來和標準的 PHP 程式碼一樣。 然而,Membership 類實際上是標準的 .NET 類。 Phalanger 會把 PHP 類和 .NET 類同等對待,所以我們可以使用標準的語法來呼叫 .NET 方法。 函式 ValidateUser 和 GetUser 都是靜態函式,所以使用::語法來呼叫。 GetUser 的結果是一個 .NET 的 MembershipUser 物件, 其中帶有各種屬性,包括關於使用者的基本資訊。 我們仍然可以使用標準的標記法來訪問物件的欄位(它們被實現為 .NET 的屬性)。

正如你所看到的,我們可以很自然地在 PHP 中使用 .NET 功能。 由於程式碼會被編譯成 .NET 程式,所以在呼叫 .NET 庫時不會有任何負載。 下一部分展示的是反方向的整合——從 .NET 應用程式中呼叫 PHP。

方案3: 從   應用程式中呼叫 PHP

PHP 的主要優勢就在於靈活性和簡單性,這使得它成為編寫指令碼和實現渲染 HTML 很棒的語言。 然而,有些人發現,想要實現大型應用程式,那麼在靜態型別語言——像 Java 或C#——會更容易一些。 使用 Phalanger,我們可以同時獲得兩方面的優勢。

這個部分所討論的方案演示了一種組合   和 PHP 的方式。 它基於先進的  MVC(模型、檢視、控制器)框架,將表現層、負責互動的層和應用程式的業務邏輯分離開來。 我們可以使用不同的語言來開發單獨的元件:

C#模型和控制器 模型和控制器會在 C# 中編寫。 應用程式的這個部分會實現業務邏輯,通常這在靜態型別語言中編寫更容易一些,特別是在業務邏輯非常複雜的情況下。 此外,我們還可以使用像 LINQ 之類的技術來儲存資料,使用任務並行庫(Task Parallel Library)使用多執行緒來實現高效能運算。
PHP 檢視 應用程式的表現層會用 PHP 編寫。 在這裡,PHP 的簡單性和靈活性會提供最大的好處。 此外,這意味著應用程式的這個部分可以由開發經驗比較少的開發者來編寫,因為大多數 web 開發者的 web 設計師都對 PHP 有些瞭解。
還有一些情況,從 C# 中呼叫 PHP 會很有用。 例如,你可以在大型的 C# 專案中使用 PHP 作為指令碼語言。 這也非常有用,因為 PHP 是一種廣為所知的語言。 另一種情況是,當在 C# 中使用 PHP 程式庫的時候——正因為有了 Phalanger 的 duck typing 機制,這才得到了很大程度的簡化,該機制甚至可以為呼叫文件齊備的 PHP 程式碼生成靜態型別的 C# 介面。

在本文剩餘的內容中,我們會著重討論使用 PHP 實現   應用程式表現層的方案。 你可以在文章末尾找到其他方案(像編寫指令碼)的參考資訊。

在 C# 和 PHP 中建立模型-檢視-控制器應用程式

首先讓我們看下使用 C# 和 PHP 組合建立出來的簡單應用程式。 應用程式的模型和控制器都是使用 C# 編寫的,如程式碼 2 所示。在這個例子中,模型只是一個簡單的 C# 類,它表示的是產品資訊。 在現實情況下,這個類可能會負責從資料庫載入資料,並且可能使用 LINQ 來實現。

程式碼2: 示例 web 應用程式(C#)的模型和控制器

public class Product {
public string ProductName { get; set }

public double Price { get; set }

}

public class HomeController : Controller {

public ActionResult Index () {

ViewData.Model = new Product { ProductName = “John Doe”, Price = 99.9 };

return View ();

}

}

控制器元件是透過 HomeController 類實現的,它會繼承   MVC 控制器。 類中只包含一個動作,展現應用程式的索引頁面。 當使用者訪問/Home/Index(或者根 URL)的時候就會觸發這個動作。 它會建立模型(Product 類的例項)並把它傳遞給檢視元件。

在標準的   MVC 應用程式中,檢視元件通常會使用 ASPX 頁面或者使用帶有使用 C# 或 Visual Basic 編寫的程式碼的 Razor 檢視來實現。 Phalanger 讓我們可以使用 PHP 來實現檢視。 程式碼 3 展示了這個例子。

程式碼 3 示例 Web 應用程式(PHP)的檢視

head>

Product Listing using Phalangerh1>

Product: $MODEL->ProductName; ?>

Price: $MODEL->Price; ?>

body>html>

檢視會使用下面描述的   MVC 擴充套件來渲染。 擴充套件會執行程式碼 3 中所示的 PHP 指令碼,並定義名為 M O D E L MODEL 的全域性變數,其中會包含控制器返回的資料。 在上述示例中, M O D E L MODEL 是對標準 .NET 類的引用。 Phalanger 會對 .NET 類和 PHP 物件同等對待,所以使用 echo 結構,我們很容易就可以顯示產品的屬性。

示例顯示了應用程式的基本結構,但是它極為簡單,所以不會真正顯示出在表現層使用 PHP 所能給我們帶來的好處:

PHP 與生俱來的動態特性使得渲染任何結構的資料都很簡單。 檢視並不僅限與簡單指令碼,並且可以使用任何現存的 PHP 庫,包括流行的模板引擎(templating engines)。
檢視可以使用 PHP 的 include 功能實現多檔案的結構,這樣你可以完全控制頁面如何生成。
建立檢視的開發者不需要知道任何關於 .NET 的知識。 這意味著從 PHP 轉型為 C# 的公司,仍然支援現存的開發者技能。
為了讓你更好地瞭解這個方案的工作方式,以下部分會說明關於 PHP 和 C# 整合的技術細節。 如果你對細節不感興趣,那麼就可以直接跳到總結部分。

透過現象看本質

這個部分所描述的方案基於 PicoMVC 專案【4】,它讓我們可以組合 PHP 和F#。 為了讓示例更簡單,我把程式碼從F#轉換為C#。 在 PicoMVC 中 PHP 整合的核心是一個簡單的函式,它會取得 PHP 指令碼的檔名,並使用 Phalanger 執行時來執行。 函式如程式碼 4 所示。

程式碼 4 從   web 應用程式呼叫 PHP 指令碼

void PhalanagerView (string fileName, object model, HttpContext current) {
// Initialize PHP request context and output stream

using (var rc = RequestContext.Initialize (ApplicationContext.Default, current))

using (var byteOut = HttpContext.Current.Response.OutputStream)

using (var uftOut = new StreamWriter (byteOut)) {

// Current context for evaluating PHP scripts

var phpContext = ScriptContext.CurrentContext;

// Redirect PHP output to the HTTP output stream

phpContext.Output = uftOut;

phpContext.OutputStream = byteOut;

// Declare global $MODEL variable (if model is set)

if (model != null)

Operators.SetVariable (phpContext, null, “MODEL”,

ClrObject.WrapDynamic (model));

phpContext.Include (fileName, false);

}

}

PhalangeriView 方法會獲得檔名(指向 PHP 指令碼)、代表作為模型返回的資料的 .NET 物件以及當前的 HTTP 上下文。 它首先會初始化 RequestContext,從而 Phalanger 知道它是在處理作為 HTTP 請求一部分的指令碼。 然後,它會確保所有 PHP 指令碼生成的輸出都會直接作為 HTTP 響應傳送。 當作為指令碼執行 PHP 的時候,輸出可以重定向到記憶體流,從而以不同的方式處理。 最後,方法會宣告全域性變數 MODEL,並使用 Phalanger 所提供的 Include 方法來執行 PHP 指令碼。

這個例子並不完全是從 C# 呼叫 PHP 的指引,你可以在 Phalanger 部落格的文章中找到更詳細的資訊。 然而,它應該可以說明,使用 Phalanger 從 C# 呼叫 PHP 指令碼相當容易。 這在本節討論的 web 程式設計情況下會很有用,但是它給了我們更多選擇。

總結

本文簡要地介紹了 Phalanger——針對 .NET 的 PHP 編譯器——以及幾種方案,我們可以在實踐中使用它來解決重要問題。 最近 Phalanger 專案非常活躍,2.1版本中包含了很多相容性方面的改善、使用動態語言執行時(DLR)以獲得更好的效能,以及與 Visual Studio 2010 的整合。

我們看了三種可以在 web 開發中使用 Phalanger 的方案。 第一種方案是使用 Phalanger 在 Windows 環境下執行未經修改的開源 PHP 專案(像 WordPress)。 使用 Phalanger 編譯的應用程式可以執行在   下,這種主機會更輕量級,執行效率也更高。

在第二種方案中,我們檢視了整合在 .NET 生態系統中的 PHP 應用程式。 有了 Phalanger 擴充套件,我們就可以在 PHP 程式碼中直接呼叫 .NET 程式庫。 例如,這可以用來整合   應用程式和 WordPress 之間的使用者資料庫。

最後一種方案演示了一種 web 框架,它使用 PHP 作為在   MVC 中編寫檢視的語言。 透過這種方式,.NET 開發者可以很容易地提供應用程式的業務功能,而 PHP 開發者可以在表現層中直接使用它。

關於作者

Tomas Petricek是微軟的C# MVP 和F#佈道師。 他和 Jon Skeet 一起編寫了《Real-World Functional Programming》一書,說明了函式式的概念,並向有 C# 背景的開發者說明如何使用F#。 Tomas 還是 DEVSENSE 的共同創始人,他對很多開源專案都做出了貢獻,包括 Phalanger 和F#語言針對 MonoDevelop 的整合。

參考資訊

[1] The Phalanger 網站包含了關於專案的最新訊息。

[2] 文件和介紹(Phalanger Wiki)

[3] Phalanger 2.1下載包括安裝程式和原始碼(CodePlex)

[4] PicoMVC 專案使用 Phalanger 作為輕量級的檢視引擎(Robert Pkckering 的 Strange 部落格)

[5] PHP 作為針對 C# 的指令碼語言 討論了另一種對 Phalanger 的用法(Phalanger 部落格)

[6]以型別安全的方式在 C# 中使用 PHP 物件(Using PHP objects from C# in a type-safe way) 說明了 Phalanger 提供的,用於從 C# 訪問 PHP 物件的安全機制。

[7]Phalanger 利用 DLR 的優勢宣佈了 Phalanger 2.1 的釋出(Phalanger 部落格)

[8] Jadu CMS 和 Microsoft .NET ——使用 Phalanger 把 PHP 應用程式編譯到 .NET 的案例學習 [9]Phalanger 支援包含了額外託管的 PHP5 擴充套件(DEVSENSE)

[10] Phalanger 評測 包含額外的效能資訊

轉載出處:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69911024/viewspace-2639946/,如需轉載,請註明出處,否則將追究法律責任。

相關文章