|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Downloads
ContentsPhalanger is a PHP language compiler for Microsoft .NET platform. In the 1.0 version the primary goal was to be able to compile any existing PHP application, but in the 2.0 version of Phalanger, PHP became first-class .NET citizen. In this article I'd like to describe the most important and interesting features in the Phalanger project from .NET developers point of view. This means that I will focus a bit more on .NET, interoperability and possibilities to extend PHP applications using other .NET languages, than on the Phalanger support for running existing PHP applications.
Phalanger OverviewAs I said earlier, the 1.0 version Phalanger was focused only on compiling existing PHP applications for .NET framework. The 2.0 version added the goal to allow interoperability between PHP and .NET world. This means that in 2.0 version it is possible to use most of the .NET objects right from the PHP code. To make this possible, Phalanger extends the PHP syntax in a few important ways (but it is still fully backwards compatible). The language extensions are called PHP/CLR. I will write about these later, but in a nutshell it allows you to use .NET features like generics and custom attributes from PHP and also to use C#-like compilation mode (in which application consists of classes instead of scripts). Phalanger became an open source project in 2.0 version and it was released under Microsoft Shared Source Permissive License (it allows commercial usage, modification, and redistribution, see the license for details). You can find more information about the project at Phalanger home page , which contains Phalanger wiki, articles and news or Phalanger home at CodePlex where you can find latest releases, source code, discussions and issue tracker. Phalanger is stable enough to be used in enterprise applications and Skilldrive company is using Phalanger.
Running Php Applications On PhalangerFirst I'd like to write about the possibility to run existing PHP applications on .NET Framework using Phalanger. The example of such web site is our web (http://www.php-compiler.net/) which is based on an excellent wiki written in PHP called DokuWiki [^]. The list of applications that work well with Phalanger is still growing and currently contains for example PhpBB (Forum system), PhpMyAdmin (Admin for MySQL) and DokuWiki. Phalanger Configuration(click on the image for a large version)If you want to configure existing application to use Phalanger, you need to follow the following simple steps:
PHP extensions supportTo make Phalanger as compatible with standard PHP implementation as possible, we provide way for using native PHP4 extensions. Most of the popular PHP extensions like Let's start with very simple example that prints names of months in gregorian calendar. It uses function <ol> <?php $nf = cal_info(CAL_GREGORIAN); foreach($nf["months"] as $m) echo "<li>$m</li>"; ?> </ol> As you can see, nothing special appeared in the PHP source code. To tell Phalanger what native extensions you want to use, you must include it in the <?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<!-- http handler as in perevious sample -->
</system.web>
<phpNet>
<classLibrary>
<add assembly="php_calendar.mng, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=4ef6ed87c53048a3"
section="calendar" />
</classLibrary>
</phpNet>
</configuration>
Also please note, that you need to install the managed wrapper to the GAC. Managed wrapper is library that contains interface used by Phalanger for calling the extension. Phalanger installer does this automatically, but if you want to do it manually, you can find managed wrappers in the Php As A First-class .Net CitizenThanks to the Phalanger project you can use PHP as a language for developing almost ANY .NET project. You can also add code that uses .NET to existing PHP application (which uses the PHP scripting model), but this will be discussed later (section 5.1). Why would you want to use PHP? There are a few very important reasons - first, there is a lot of existing PHP code, which works very well and doesn't have equivalent in the .NET world, also many people who know PHP might want to experiment with .NET, but don't want to learn another language or just prefer PHP. PHP itself is a dynamic language, which means that it can be very simple and it is easier to solve some tasks in it. You can also use it very well to combine together more components written in another languages, because dynamic languages serve this purpose very well. My favorite example which shows the power of PHP language is working with XML using SimpleXML extension: <?php
// load the RSS feed
$xml = simplexml_load_file
("http://www.nytimes.com/services/xml/rss/
nyt/HomePage.xml");
// print the contents of 'title' element
echo $xml->rss->channel->title."\n";
// print latest posts
echo "Latest posts:\n";
foreach($xml->rss->channel->xpath("item") as
$item)
{
echo " - ".$item->title."\n";
}
?>
I think that the code is very self-explanatory. The dynamic language "trick" here is using standard member notation ( Visual Studio SupportAs a first-class .NET language, you can also create PHP applications in Visual Studio. The Phalanger extensions are not part of the core Phalanger installer, so you'll need to download it separately. Due to the Visual Studio limitations, it is not possible to use Phalanger extensions with the VS Express versions. (Click on the image for full screenshot [^])The following overview describes what projects you can develop using Phalanger in Visual Studio:
Thanks to the great .NET support debugging it is also possible to debug PHP applications (running on Phalanger) in the Visual Studio (as you can see on the screenshot). During the debugging you can also use watches and locals, but because of the dynamic nature of the PHP language, you may need to search for the variable value in the hashtable, where the value is often stored. The Visual Studio support is still in early phase of development and we're still working on improving the editing and debugging experience. Pure vs. Legacy ModeIn standard PHP the scripts are executed sequentially. This means that application execution starts with one main script, the global code in this file is run line by line and eventually other scripts can be included using On the other side, the pure mode is more similar to the logic known from C#. In this mode scripts are merged together during compilation (and no inclusions are allowed) and every script can contain only top-level declarations of classes and functions. The entry point is static function called PHP/CLR Language ExtensionsLet's look at the PHP language extensions called PHP/CLR that allows you to use .NET objects in Phalanger. Note that these extensions can be used in both legacy and pure mode, which means that you can use .NET objects from existing PHP application as you'll see later. CLR objects and namespacesSince all .NET libraries are ogranized in the structure of namespaces you have to be able to use namespaces in PHP when you want to use .NET libraries. Namespaces that are available in Phalanger are based on the PHP 6 proposal and it allows you to organize your PHP code into namespaces as well as use existing CLR namespaces. In PHP 6 proposal, the operator used for accessing namespace is <?php
$rnd = new System:::Random;
echoNext(10);
?>
You can also use the import namespace statement to make the code simpler <?php
import namespace System;
$rnd = new Random;
echoNext(10);
?>
Now you know how to use classes from existing namespaces (and you can even use CLR classes from CLR namespaces!). To run this example you'll need to add following to the application config file: <?xml version="1.0" encoding="utf-8"?>
<configuration><phpNet>
<compiler>
<set name="LanguageFeatures">
<add value="PhpClr" />
</set>
</compiler>
<classLibrary>
<add assembly="mscorlib" />
<add assembly="System, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</classLibrary>
</phpNet></configuration>
This tells Phalanger two things - first that you want to enable PHP/CLR language extensions (that include namespaces etc.) and second - that you're using CLR classes and you want to reference specified .NET assemblies. To build this application you can create new Legacy Console Application (from Phalanger project templates) - note that we used legacy application, which means that it is possible to use global code in the script file. Second option for building is to use the following command from Phalanger command line (this will also produce console application): phpc /lang:CLR program.php IdentifiersNext useful extension to the standard PHP syntax allows you to write identifiers that conflict with PHP keywords. This is similar to the <?php // Calls function called 'function' i'function'("Hello world!"); ?> GenericsIn the paragraph I mentioned that you can use generic classes like <?php import namespace System:::Collections:::Generic; // Add values to dictionary $d = new Dictionary<:string,string:>; $d->Add("cz", "Ahoj svete!"); $d->Add("en", "Hello world!"); $d->Add("fr", "Salut le Monde!"); $d->Add("de", "Hallo Welt!"); // OK - Implicit int to string conversion $d->Add(0, "Something less evil!"); // Invalid - can't add instance of Random as a key // $d->Add(new System:::Random, "Something more evil!"); // Read value $out = ""; if ($d->TryGetValue("cz",$out)) echo $out; ?> There is also one interesting thing to note - because we want to keep dynamic nature of the PHP language, we also allow specifying the generic type parameter using variable, so for example if you have variable As you expect, you can also declare new generic class that takes generic parameters in PHP using PHP/CLR extension. Because PHP doesn't require as strict type checking as for example C#, you can use default values to specify the default type that will be used if the type is not specified when calling the function or instantiating the class. The following code shows some examples: // Inherited dictionary class PhpDict extends Dictionary { /* ... */ } // Inherited list with default type parameter class PhpListobject extends i’List’ { /* ... */ } // Function with one type parameter function PhpFunc { /* ... */ } Custom AttributesAnother very important concept in .NET that doesn't have good equivalent in PHP language are attributes that you can use to annotate source code and to add some additional information to your classes, methods, etc. Attributes are used for many important scenarios - for example if you are creating web service you use The support for attributes is currently a bit limited (if you want to write web services in PHP you'll have to wait for the next build), so I will use simpler example to demonstrate using attributes with PHP. In the example I will use <?php import namespace System:::ComponentModel; [Description("Description for the function foo")] function foo($a) { echo $a; } ?> As you can see, the syntax is the same as in C#. We are also planning to support named parameters with C#-like syntax, but as I mentioned this is still under development (If you are considering using Phalanger and need to use this feature, let us know so we can focus on what users need!). We also introduced two pseudo-attributes that are treated differently by the compiler - you can use them to instruct compiler, how the generated code should look like. The first attribute is <? class Counter { [AppStatic] public static $N; } // display and increment counter value echo Counter::$N; Counter::$N++; ?> Other ExtensionsThere are also a few other extension that we will not discuss in detail, so I will write just a short overview of these features availble in PHP/CLR. We added support for partial classes (this makes sense only in pure mode), because this is important to allow working with ASP.NET and other technologies that generate part of the source code in .NET 2.0. We're also working on adding properties (with getter and setter method), because this is useful when inheriting from CLR class. Currently you can override inherited property only by creating class member (which is PHP equivalent to the .NET field) with the same name. And finally, we also announced that we are working on supporting the LINQ project [^] as part of PHP/CLR to make data access in PHP even easier. Phalanger Legacy Compilation ModeYou already seen a few examples that demonstrated working with .NET objects in PHP. The most of the previous examples (you can get the full versions in attached zip file) used legacy compilation mode, which is just easier to use for simpler tasks. As you can see from the previous examples you can "inject" code that uses .NET CLR objects to any PHP application including complex PHP applications, because it doesn't matter whether you use legacy mode (PHP compatible) or pure mode (only in Phalanger). Thanks to this possibility you can for example use your data access layer written in C# from PHP application that presents the content to the user! Using .Net Objects From PhpLet's look at the sample application (the full source code is one of the attached demos) that uses layered architecture and has data access layer/business logic written in C# and presentation layer written in PHP. The application is very simple and it uses products and categories from the SQL Server Northwind database. The data layer contains classes that represent product and category with several properties and class
The // Returns all categories
public List<Category> GetCategories()
{
List<Category> ret = new List<Category>();
using(SqlConnection cn = new SqlConnection(connStr))
{
// Select all categories from database
cn.Open();
SqlCommand cmd = new SqlCommand
("SELECT [CategoryID], [CategoryName] FROM
[Categories]", cn);
using (SqlDataReader reader = cmd.ExecuteReader())
{
// Add all categories to the list
while (reader.Read())
{
ret.Add(new Category((int)reader["CategoryID"],
(string)reader["CategoryName"], GetTheme(
(int)reader["CategoryID"])));
}
}
}
return ret;
}
Now that we have data-access layer we can look how to use it from PHP. First you need to create Visual Studio project (however you can just create directory mapped in IIS and put all your files in it) - in the menu select File - New Project and then in the Phalanger category select PHP Web Application. Probably the most difficult part is to configure Phalanger correctly. You already saw how to configure HTTP handler in web.config, how to enable PHP/CLR language extensions and how to add reference to assembly that you want to use in PHP code, so you know everything to do this correctly. The <?xml version="1.0"?>
<configuration>
<!-- configure ASP.NET -->
<system.web>
<httpHandlers>
<add verb="*" path="*.php" type="PHP.Core
.PageFactory, PhpNetCore,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=
0a8e8c4c76728c71" />
</httpHandlers>
</system.web>
<!-- configure Phalanger -->
<phpNet>
<compiler>
<set name="LanguageFeatures">
<add value="PhpClr" />
</set>
</compiler>
<classLibrary>
<add assembly="mscorlib" />
<add assembly="DemoDataLayer" />
</classLibrary>
</phpNet>
</configuration>
You can see that in the Now we can write PHP script that will display the list of categories on the project home page: <? // load data layer import namespace DemoDataLayer; $dl = newGetCategories(); ?> <html><body> <h1>Categories</h1> <ul> <? // Write link to detail for every category foreach($categories as $c) { ?> <li><a href="products.php?id=<? echo $c-> ID ?>"><? echo $c->Name ?></a>< /li> <? } ?> </ul> </body></html> The first line contains The source code of more complete example can be found in the attached demos. Combining data access layer written in C# with presentation layer in PHP is very powerful, because it gives you the safety of C# where you need it and the simplicity and flexibility of PHP where you can benefit from it. Phalanger Pure Compilation ModeIn the introduction I wrote about the differences between legacy and pure mode. If you want to use existing PHP source (developed for standard interpreter) without modifications you have to use legacy mode, but when you want to develop new PHP project you can consider using pure mode. The pure mode is required if you are developing application based on ASP.NET 2.0 and it is recommended for developing Windows Forms applications too. It also gives you a possibility to make objects written in PHP available to other .NET languages, because you can instruct compiler to generate overloads that can be easily used from C#. Using Php Objects Other .Net LanguagesI will start with an example that shows how to write object accessible from C#. When compiling PHP objects, the class generated by Phalanger doesn't contain methods with arguments that you would expect - the reason for this is that PHP is dynamic language and there is internally quite complex mechanism for method invocation. For example if you compile class called // First generated overload
public virtual object Foo(ScriptContext ctx);
// Second (static) method
public static object Foo(object instance, PhpStack stack);
I didn't want to scare you with the previous example, I just wanted to explain why calling PHP objects from C# wouldn't be as simple as it might look if we didn't implement special option to makes it easy! This option is called <? namespace PhpClassLib { // Export tells compiler to generate methods that // can be used from other .NET languages [Export] class DynamicObject { var $obj; // Creates object by class name function __construct($obj) { $this->obj = new $obj; } // Dynamically calls method function Call($name) { return $this->obj->$name(); } } } ?> After compiling the code (either using Visual Studio and creating new Phalanger Class Library or using command line // Constructor
public DynamicObject(object obj);
// Call method
public object Call(object name);
It is obvious that in language with no static typing, the arguments and return types of the functions must be the // Note that the name passed to the object uses PHP namespace notation
DynamicObject obj = new DynamicObject("System:::Random");
int n = (int)obj.Call("Next");
Console.WriteLine("Returned = {0}", n);
And you didn't have to use any class from the Windows Forms ApplicationsClick on the image for original screenshot.You can also use Phalanger to develop Windows Forms applications. WinForms are interesting topic because it requires creating event handlers. Our implementation of event handlers doesn't require any modifications to the language, but it is significant part of allowing PHP to interoperate with .NET classes. Many people write Web Applications in PHP, but what about writing Web Browser? It isn't that difficult, but I'll start with typical "Hello world!" example. You can find the web browser sample in attached demos (yes, it is based on IE ActiveX control and no, it doesn't support tabbed browsing currently ;-)). I made the sample as simple as possible, so I put the <? import namespace System; import namespace System:::Drawing; import namespace System:::Windows:::Forms; class MainForm extends System:::Windows:::Forms:::Form { function __construct() { // Form properties $this->ClientSize = new Size(400, 400); $this->Text = 'PHP Hello world!'; // Create button $btn = CreateCtrl("Button", array( "Left" => 10, "Top" => 10, "Width" => 380, "Height" => 380, "Text" => "Click me!"Add($btn); // Set event handler $btn->Click->Add (new EventHandler(array($this, "btnClicked"))); } // Show message box when button is clicked function btnClicked() { MessageBox::Show("Hello world!"); } // Entry-point function static function Main() { // Enable XP visual styles and start with MainForm Application::EnableVisualStyles(); Application::Run(new MainForm()); } } ?> In the previous code we used the // Helper WinForms function function CreateCtrl($name, $props) { // Create instance of control with specified name $ctl = new $name; // Set all control properties foreach(array_keys($props) as$prop = $props[$prop]; return $ctl; } You may be wondering how this works internally when it is compiled as .NET assembly. The invocation itself doesn't use Reflection which makes it very efficient. It consumes some CPU when first indirect call is used, to generate some internal data structures, but later it works very well. This would be probably a topic for another article, so I won't describe the details here. Asp.Net 2.0 ApplicationsNow I'd like to show how you can use PHP as a language for developing ASP.NET 2.0 application. You can also visit our web site and download well known application - Personal Web Site StarterKit ported to PHP (See our releases page [^]). By ASP.NET 2.0 application I mean an application that is based on the ASP.NET 2.0 object model that you can use with C# or VB.NET including code-behind, ASP.NET controls, master pages, themes etc. This is useful if you want to use ASP.NET object model, but you prefer PHP as a language for some reason - for example you have big experiences with PHP or you want to use some code written in PHP that you already have. To create new ASP.NET 2.0 Phalanger application, select File - New - Web Site in Visual Studio, in the languages box select PHP and then choose "ASP.NET Web Site". The template contains two files - <%@ Page Language="PHP" CodeFile="Default.aspx.php"
Inherits="DefaultPage" %>
<html><head runat="server">
<title>Phalanger ASP.NET Demo</title>
</head><body>
<form id="form" runat="server">
<!-- Demonstrates inline PHP code (use standard
ASP.NET <% .. %> -->
<%
// Prints header with random color
srand((double)microtime()*1000000);
$colors = array("#800000", "#008000",
"#000080", "#606000", "#600060", "#006060");
echo "<h1 style=\"color:".$colors[rand(0,6)].
"\">Phalanger ASP.NET Demo</h1>";
%>
<!-- Some ASP.NET controls -->
Enter your name: <asp:TextBox runat="server" id="txtName" />
<asp:Button runat="server" text="Ok" id="btnOk"
OnClick="btnOk_Click" /><br />
<h2><asp:Label runat="server" id="lblOutput"
/></h2>
</form>
</body></html>
This source shows the Even though you have to use ASP.NET style tags, you can use any PHP functions, because Phalanger implementation is built on top of ASP.NET framework, so most of the function will integrate well with ASP.NET. If you're using ASP.NET Phalanger compiles the source code in pure mode which means that you can't use <? import namespace System; // Partial code-behind class partial class DefaultPage extends System::Web::UI::Page { // Called when user clicks on the button function btnOk_Click($sender,$e) { // lblOutput and txtName are declared in // second part of partial class $this->lblOutput->Text = "Hello ".$this->txtName->Text."!"; } } ?> As you can see, we need to use Other NotesMono SupportThe Phalanger version 2.0 supports the Mono platform (in the first version it was impossible, because part of Phalanger was written in Managed C++). The biggest limitation is, that you can't use native extensions, which are supported only on Windows. There are a few more issues under Mono, but we're working on resolving these. Mono allows many interesting scenarios - you can use Phalanger with Apache web server and mod-mono extension that allows you to run PHP web applications powered by Phalanger, or you can use PHP for developing portable Mono applications. You can also use any Mono library from Phalanger, so you can for example develop GUI application using the Gtk# library. BenchmarksBecause Phalanger compiles PHP applications to the CLR the execution of applications is faster when compared to standard PHP interpreter. The efficiency relies on the Phalanger runtime and the CLR itself. Because several features that allow better compilation of dynamic languages were added in the 2.0 version, the Phalanger 2.0 is faster than the 1.0 version. We tried two kinds of performance tests - the micro-benchmarks show how fast is the execution of the most important elementary operations (like calling a function, calling function by name, array access, etc.) on Phalanger and PHP interpreter. The results are very good - from the 25 tests in total, Phalanger is faster in 19 tests and the difference in the 6 remaining tests is very small. The second test compares performance of the PhpBB forum application running on PHP and Phalanger. The results show that Phalanger was able to serve almost two times more pages per second!
Authors and historyThe Phalanger project started at the beginning of the year 2003 as a student project code-named PHP.NET at Faculty of Mathematics and Physics [^], Charles University in Prague [^], Czech Republic. The members of the project during the development of first version were Tomas Matousek [^], Ladislav Prosek, Vaclav Novak, Pavel Novak, [^], Jan Benda [^], and Martin Maly [^]. The aim of the project was to find out whether the compilation of dynamic languages (particularly the PHP language) is possible on .NET Framework and whether it could result to any performance improvements when confronted with the interpreter and various acceleration tools. After successful defense, the members of the project team continued to contribute to Phalanger on volunteer basis for more then a year. The goal was to provide a functional compiler and runtime compatible with PHP versions 4 and 5 and the final version 1.0 was released in February 2006. In March 2006, Tomas Matousek and Ladislav Prosek started to design and implement the 2nd version of Phalanger. Based on their presentations of Phalanger at the Compiler Lab in Redmond, they received a generous support from Microsoft Corporation. The version 2.0 is based on the previous one, however, some parts were completely redesigned and rewritten and it introduced the new PHP/CLR language extensions. In October 2006 Tomas and Ladislav moved to Redmond and started working at Microsoft in the CLR team and Tomas Petricek become the new project leader and started working with the new development team on completing the 2.0 release as well as publishing more articles about the Phalanger.
Links and References
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||