使用 Phalanger 整合 PHP 和 .Net

Phalanger 是一種 PHP 語言編譯器,也是針對 .NET 的 PHP 運行時。 它能夠用於把 PHP web 項目編譯成 .NET 字節碼,並在 Windows 中使用 IIS 或者在 Linux 上使用 Mono 和 Apache 做爲 ASP.NET 應用程序來執行。 然而,Phalanger 不只僅是把已經存在的 PHP 應用編譯到 .NET 中。php

咱們可使用 Phalanger 建立組合 .NET 和 PHP 的解決方案,所採用的方式用標準的 PHP 解釋器是不可能作到的。 有了 Phalanger 擴展,PHP 程序能夠直接使用 .NET 類,而 .NET 程序(比方說用 C# 編寫的)也能夠動態地調用 PHP 腳本,或者使用在 PHP 中實現的函數和類【6】。html

本文中,我麼會簡要地介紹 Phalanger,而後查看三種使用方案。 咱們會討論如何整合 PHP 應用程序和 .NET;如何高效地在 Windows 上運行 PHP 應用程序,以及如何使用 PHP 做爲 ASP.NET 的視圖引擎(view engine)。web

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 與 ASP.NET 整合。 使用 Phalanger 編譯的 PHP 代碼可以調用全部 .NET 程序庫。 這能夠用於在 PHP 和 ASP.NET 應用程序之間共享用戶數據庫或者其餘數據。
方案3: 從 ASP.NET 應用程序中調用 PHP。 PHP 的靈活性對於編寫腳本或者編寫 web 應用程序的表現層很是有用。 有了 Phalanger,咱們就能夠在 .NET 中開發應用程序,並使用 PHP 做爲腳本語言或者視圖引擎。
如下三個部分會詳細討論各類方案。 咱們首先會給出概覽,而後查看一些技術細節,它會說明 Phalanger 中讓你感興趣的內容。

方案1: 高效運行 PHP 應用程序

Phalanger 之因此可以高效地運行 PHP 應用程序,是由於如下兩個緣由。 首先,它會編譯 PHP 源代碼,而不是解釋它;其次,它會把應用做爲 ASP.NET 應用程序運行,那會在 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 進行了進一步優化。

使用 ASP.NET 部署 PHP 應用程序

Phalanger 應用程序的運行方式和 ASP.NET 應用程序徹底相同。 這讓它具備了重要的性能優點,特別是在 Windows 系統下,進程要比線程耗費更多資源。

圖 2 顯示了運行 PHP 應用程序的不一樣可選方案。

當使用標準 CGI 模式時,web 服務器會爲每一個進入的請求啓動新的進程。 在 Windows 下,這樣作的效率不高,它還阻止了共享位於共享內存中的狀態,也很難進行進程中緩存(in-process caching)。 當使用 FashCGI 模式時,web 服務器會重用進程,這樣它不須要爲每一個請求啓動新的進程。 然而,這仍是沒法共享內存中的狀態,由於不一樣的進程擁有不一樣的狀態。

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

Phalanger 的行爲方式和全部 ASP.NET 應用同樣。 單獨的叫作應用池(Application Pool)的 ASP.NET 進程會處理全部進入的請求。 咱們甚至能夠在單一進程(應用池)中配置多個 PHP 應用程序(像多個 WordPress 的獨立實例)。 在進程中,會有多個線程,這些線程會被重用以處理單獨的請求。 在 Windows 下,線程要比過程更輕量級,因此這種解決方案更有效率,而且會消耗更少的內存。

對於運行在單一進程中的應用程序,咱們能夠進行進一步的優化,並採用其它有趣的方案。 例如,Phalanger 會使用動態語言運行時(DLR)來作動態方法調用。 DLR 會使用與時間相適應的緩存機制,所以在幾回請求以後,DLR 就會「知道」應用程序使用的是哪一個方法,並變得更快一些。 這隻有在單一進程中處理請求的狀況下才可能作到。

在單一進程中運行全部代碼也意味着應用程序能夠在內存中存儲全局狀態。 這能夠用於實現與 WinCache 提供的 User Cache 相似的功能,可是不會有跨進程通訊形成的負載。

方案2: 把 WordPress 與 ASP.NET 整合

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

這些應用一般會比 .NET 平臺下相似的程序包提供更多特性。 開發基於 ASP.NET 網頁的公司可能會面臨如下狀況:

它須要向現存的 ASP.NET 解決方案中添加 wiki、論壇或者博客,可是隻有在 PHP 中存在合適的應用程序(例如,免費而且帶有全部必要特性)。
應用程序可能會在子域下運行,可是它應該共享用戶數據庫。 此外,一旦用戶登陸到主頁,那麼他就應該同時登陸到 wiki、論壇和博客上。
ASP.NET 應用程序可使用 ASP.NET 的成員管理(ASP.NET Membership),它還用來管理用戶、角色和功能的標準機制。 有了 Phalanger,咱們就能夠修改開源的 PHP 項目,從而使用一樣的機制。 下一部分會演示使用 WordPress 如何作到這一點。

爲 WordPress 實現 ASP.NET 成員管理插件

若是你對代碼不感興趣,那麼就能夠略過這個部分,直接查看第三種狀況。 可是,咱們不會查看技術細節,只是對讓 PHP 調用 .NET 程序庫的 PHP 擴展作簡要的概述。

咱們可使用插件輕鬆地自定義在 WordPress 管理用戶的方式。 管理用戶的插件須要實現一個 PHP 類,其中有各類成員函數。 其中最值得期待的功能就是身份驗證,它會得到用戶名和密碼。 它應該填充當前用戶的信息,或者,當用戶不存在的時候,就會把名稱設置爲 NULL。

爲了使用 .NET 中的 ASP.NET 成員管理來實現身份驗證功能,咱們可使用 System.Web.Security 命名空間中的功能。 靜態方法 Membership.ValidateUser 會檢查密碼是否正確,而 Membership.GetUser 會返回用戶的基本信息。 使用 Phalanger,咱們能夠訪問 .NET 對象,就像它是標準的 PHP 對象同樣,這樣實現驗證機制就很簡單了。 代碼 1 展現了簡化後的代碼。

代碼 1 在 WordPress 插件中實現身份驗證功能的函數

import namespace System:::Web:::Security;
function authenticate (&username,username,username,password) {

global $errors;

// Test whether the password is correct

if (Membership::ValidateUser (username,username,username,password)) {

// Get information about the user and fill $userarray

user=Membership::GetUser(user = Membership::GetUser (user=Membership::GetUser(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 (id=usernameexists(id = username_exists (id=usernameexists(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: 從 ASP.NET 應用程序中調用 PHP

PHP 的主要優點就在於靈活性和簡單性,這使得它成爲編寫腳本和實現渲染 HTML 很棒的語言。 然而,有些人發現,想要實現大型應用程序,那麼在靜態類型語言——像 Java 或C#——會更容易一些。 使用 Phalanger,咱們能夠同時得到兩方面的優點。

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

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 實現 ASP.NET 應用程序表現層的方案。 你能夠在文章末尾找到其餘方案(像編寫腳本)的參考信息。

在 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 類實現的,它會繼承 ASP.NET MVC 控制器。 類中只包含一個動做,展示應用程序的索引頁面。 當用戶訪問/Home/Index(或者根 URL)的時候就會觸發這個動做。 它會建立模型(Product 類的實例)並把它傳遞給視圖組件。

在標準的 ASP.NET 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>

視圖會使用下面描述的 ASP.NET MVC 擴展來渲染。 擴展會執行代碼 3 中所示的 PHP 腳本,並定義名爲MODELMODEL 的全局變量,其中會包含控制器返回的數據。 在上述示例中,MODEL,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 從 ASP.NET 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 編譯的應用程序能夠運行在 ASP.NET 下,這種主機會更輕量級,運行效率也更高。

在第二種方案中,咱們查看了集成在 .NET 生態系統中的 PHP 應用程序。 有了 Phalanger 擴展,咱們就能夠在 PHP 代碼中直接調用 .NET 程序庫。 例如,這能夠用來整合 ASP.NET 應用程序和 WordPress 之間的用戶數據庫。

最後一種方案演示了一種 web 框架,它使用 PHP 做爲在 ASP.NET 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 評測 包含額外的性能信息

轉載出處:http://www.iis7.com/c/90/

相關文章
相關標籤/搜索