Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / PHP

Phalanger, PHP for .NET: Introduction for .NET developers

5.00/5 (41 votes)
24 Jan 2007CPOL29 min read 1   4.1K  
Phalanger is a PHP language compiler for the .NET Framework which introduces PHP as a first-class .NET citizen.

Downloads

Contents

Phalanger 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.

  1. Phalanger overview - Introduction to the project and licensing.
  2. Running PHP applications on Phalanger - It is possible to run most of the existing PHP applications on Phalanger without (or with minor) modifications in source code. There are two interesting topics in this section - first thing is configuration which is much more flexible in Phalanger thanks to ASP.NET configuration model based on hierarchical config file structure (section 2.1), the second thing that I'd like to write about is support for extensions (section 2.2).
  3. PHP as a first-class .NET citizen - In this section I will show why PHP can be interesting language for .NET developers, we will look at the two compilation modes that are available in Phalanger (section 3.1). As a true first class citizen, Phalanger also lives in Visual Studio 2005 (section 3.1) and we will shortly look at the PHP/CLR language extensions that make it possible to use almost all .NET objects in PHP (section 3.3).
  4. Phalanger legacy compilation mode allows you to empower your existing PHP applications using .NET, but with maintaining the PHP code structure and deployment model - you can use existing PHP application and use .NET features for example in just one class or function (section 4.1). This is very useful for .NET developers who need to modify PHP applications.
  5. Phalanger pure compilation mode on the other side allows you to use PHP as a language for all modern .NET projects by modifying PHP to behave more like C# or VB.NET. In this mode, objects written in PHP can be easily used in C# (section 5.1) and you can write Windows Forms applications (section 5.2) as well as ASP.NET 2.0 applications (section 5.3).
  6. Other notes - In the last section we will look at the support for MONO in Phalanger (section 6.1). You can also find a few benchmarks here (section 6.2), which are another important reason for using Phalanger.
  7. Authors and history - Describes project history and lists all authors of the Phalanger project.

Phalanger Overview

As 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 Phalanger

First 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

IIS properties

IIS 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:

  • Install Phalanger - This registers several assemblies into GAC and registers phpNet configuration section in machine.config. If will also install and configure a few sample applications.
  • Configure IIS/Apache - I will describe Apache and Mono configuration later, for IIS you'll need to map the php extension to the ASP.NET request handler. In the Administrative tools select Internet Information Services, select your application folder or add it as a virtual directory. Select the properties of a directory with your PHP application (Image #1), click the Configure button and in the dialog add mapping for .php extension to the executable C:\WINDOWS\Microsoft.Net\Framework\v2.0.50727\aspnet_isapi.dll.
  • Add web.config file - After mapping the .php extension to ASP.NET handler, you need to add web.config to the application directory. The web.config tells ASP.NET to handle directory as an ASP.NET application, but most of the settings are configured in global machine.config file. The following snippet shows the default configuration file which just maps .php extension to Phalanger handler:
    XML
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.web>
        <httpHandlers>
          <add verb="*" path="*.php" type="PHP.Core.PageFactory,
              PhpNetCore, Version=2.0.0.0, Culture=neutral,
              PublicKeyToken=0a8e8c4c76728c71" />
        </httpHandlers>
      </system.web>
    </configuration>

    You can also configure this globally for the entire server by adding add element to the root ASP.NET web.config located in C:\WINDOWS\Microsoft.Net\Framework\v2.0.50727\CONFIG directory.

PHP extensions support

To 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 pdf, image or calendar are available in Phalanger thanks to this mechanism. Internally, this part of Phalanger is written in (unsafe) C++/CLI and it is available only on Windows platform. The native extensions can be loaded in separate process, which is secure, because failure of native extension doesn't affect the rest of application, but it is also slower. The second option is to load native extension in the same process which isn't secure, but is faster.

Let's start with very simple example that prints names of months in gregorian calendar. It uses function cal_info that returns information about calendar. This function is part of the calendar extension:

<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 classLibrary section of the configuration file:

XML
<?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 Wrappers directory. The names of the wrapper for calendar extension is php_calendar.mng.dll.

Php As A First-class .Net Citizen

Thanks 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:

C++
<?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 (-> operator in PHP) for accessing to the child elements like $xml->rss->channel->title when reading the name of RSS feed. You don't have to define any structure of the XML document and the code is very straightforward. The introduction was a bit longer, but I wanted to show why PHP as a language is interesting and why it is valuable addition to the family of .NET languages.

Visual Studio Support

As 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.

Phalanger in Visual Studio

(Click on the image for full screenshot [^])

The following overview describes what projects you can develop using Phalanger in Visual Studio:

  • PHP Web Application - creates new web application written in PHP that is compatible with the standard PHP interpreter (unless you use some Phalanger-specific features).
  • Legacy Console/WinForms Application - generates Console or Windows Forms application that is written using the legacy PHP mode in which you use global code, includes and other PHP features.
  • Console/WinForms Application - creates Console or Windows Forms application that will be compiled using the pure Phalanger mode - in this mode the PHP compiler behaves more like other .NET languages (for example C#) and doesn't allow inclusions or global code.
  • Class Library - in this project you can create .NET library using the PHP language (in the pure compilation mode) that can be simply used from other .NET languages
  • Web Projects (ASP.NET Web Site, ...) - In these three projects you can create standard ASP.NET application that uses aspx and code-behind files, but you use PHP as a language for writing in-line and code-behind code.

Phalanger .NET projects

Phalanger Projects in "New - Project..."

Phalanger web projects

Phalanger Projects in "New - Web Site..."

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 Mode

In 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 include or require directives. If you want to use this logic with Phalanger you can use legacy compilation mode (it is the default mode). In the legacy mode, scripts contain global code and if you want to use classes or functions declared in another script, you have to include it first. This mode is fully compatible with standard PHP interpreter, so you'll be able to run the application using both Phalanger and PHP.

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 Main in the selected main class. The pure mode is very interesting for .NET developers, because it allows you to use PHP language for example with ASP.NET 2.0 which depends on this object model. The standard PHP interpreter doesn't have equivalent to this mode.

PHP/CLR Language Extensions

Let'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 namespaces

Since 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 :::, so instead of System.Web you have to use System:::Web. We used this syntax, because Phalanger needs to know whether you mean class or namespace (unlike in C#, where this can be checked during the compilation). The following sample shows how you can use simple Random class from the System namespace in PHP:

HTML
<?php 
  $rnd = new System:::Random;
  echoNext(10);
?>

You can also use the import namespace statement to make the code simpler
and cleaner:

HTML
<?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
<?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

Identifiers

Next useful extension to the standard PHP syntax allows you to write identifiers that conflict with PHP keywords. This is similar to the @something syntax in C#. We had to make this possible, because some important classes from the .NET Framework (for example generic List) have names that collide with PHP keywords. For example if you have a function called function (which is an acceptable name for the C# compiler) you can call it using following syntax in Phalanger:

<?php
  // Calls function called 'function'
  i'function'("Hello world!");
?>  

Generics

In the paragraph I mentioned that you can use generic classes like List from the .NET Framework. The main reason for introducing generics in Phalanger is the ability to specify types when using .NET generic classes, but generic types may be useful for PHP developers as well - for example you can use generic collection and restrict the type that can be inserted to the collection (however this is checked at runtime as you would expect from a dynamic language). The Phalanger also allows you to write your own generic classes or functions and adds some possibilities that are unique to PHP. First simple example will show how you can use Dictionary class from .NET:

<?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 $t containing "string" you can create new instance of Dictionary using the following expression: new Dictionary<:$t, $t:>;

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 Attributes

Another 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 WebServiceAttribute to anotate the class and WebMethodAttribute to annotate all methods that you want to expose.

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 DescriptionAttribute for adding comment (that can be accessed at run-time) to the PHP function:

<?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 [AppStatic] that instructs compiler to compile field as a static field shared across the whole application (note that other static fields in PHP are shared only per-request, which corresponds to the thread-static fields in C#). The [Export] attribute controls the structure of compiled class to make it accessible from other .NET languages like C#. I will talk about this attribute later. The following example shows usage of [AppStatic] attribute. If you put the following code in script handled by Phalanger as a web application it will count requests (until the application is restarted by IIS):

<?
  class Counter
  { 
    [AppStatic]
    public static $N;
  }

  // display and increment counter value
  echo Counter::$N;
  Counter::$N++;
?>

Other Extensions

There 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 Mode

You 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 Php

Let'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 Data that is used for reading data from database. The structure of the classes is following:

Data layer diagram

The Data class contains public methods for returning all categories (GetCategories), category specified by its ID (GetCategory), all products in category (GetProducts) and one product by its id (GetProduct). All data access methods return generic List with type parameter set to Product or Category. For example, the method for reading categories looks like this:

C#
// 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 web.config file looks like this:

XML
<?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 classLibrary section of the config file we reference mscorlib assembly (that contains basic .NET classes) and DemoDataLayer assembly which is the assembly containing C# code that I described earlier. This assembly must be placed in the bin directory of the web application, so Phalanger can reference it or it can be signed using strong name key and placed in the GAC (in this case you'll have to include full assembly name in config file).

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 import namespace directive that makes it possible to use classes from data access layer without specifying the full namespace every time, after that the instance of Data class from the data access layer is created and the list of all categories is populated from the database using the GetCategories method and stored in $categories variable. Later when we need to print all the categories we can use standard PHP foreach construct to enumerate over all items in the returned list. As you would expect, you can read all properties declared in C# using the PHP syntax, so if you want to print the name of the category you can simply write echo $c->Name.

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 Mode

In 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 Languages

I 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 Test with method Foo($arg), the signature of method produced by Phalanger is following (Phalanger even generates two different methods!):

C#
// 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 [Export] attribute and you can use it for telling Phalanger that you want to use class from another .NET language. The following sample shows class written in PHP that uses PHP possibility to create instance of object or invoke method by its name - it is called indirect method access in PHP. For example if you have object stored in variable $obj and method name stored in variable $method, you can call method by name using $obj->$method(). In C# you have to use reflection to implement this. The class (I'll call it DynamicObject) has constructor that takes name of the type to create and method Call that invokes member method of the object:

<?
  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 phpc /target:dll /pure PhpClassLib.cs) you can reference the compiled dll from C# project. If you open the library in object browser you'll see that Phalanger added also following methods (in C# syntax):

C#
// 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 object type. The following example shows how you can use the class written in PHP from C# project to dynamically create instance of Random class and call its Next() method:

C#
// 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 System.Reflection namespace! This is only one of many interesting uses of the [Export] functionality. You could also use it if you want to use some functionality implemented in one of large number great PHP open source projects. The source code of the project needs to by modified a little (to make sure that it doesn't depend on inclusions and it doesn't contain any global code and then it is ready to be compiled into .NET assembly using pure Phalanger compilation mode and you can use it from any .NET language.

Windows Forms Applications

Web browser in PHP

Click 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 Main static function (the entrypoint) inside the MainForm class, which represents the window. The class contains constructor which creates controls using the powerful CreateCtrl function (I will talk about it later) and it also contains btnClicked function that is used for handling Click event of the button.

<?
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 CreateCtrl function, which I consider as very interesting! It is a function that can't be written in statically typed languages that easily. It accepts name of the control you want to create and associative array of names and values that you want to assign to the property with specified name. It is not a part of standard library, so you have to write it yourself. It uses indirect access to the properties that I mentioned earlier - this means that if we need to set Text property of an object $ctrl and we have variable $name that contains string "Text" we can also write $ctrl->$name = "Something" (the syntax for direct access is $ctrl->Text = "Something". The complete function looks like this:

// 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 Applications

Now 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 - Default.aspx which contains ASP.NET markup and Default.aspx.php which contains code-behind class. Let's look at the following example:

HTML
<%@ 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 default.aspx file. It contains standard ASP.NET @Page directive with the Language attribute set to PHP, you can also see some standard ASP.NET controls like <head runat="server" />, form, Button, Label and TextBox. The source also shows that you can use PHP as a language for the in-line code (as you can use C# or VB.NET), however you have to use ASP.NET style tags for embedding the code, because the whole page is processed by ASP.NET and Phalanger is used only for compilation.

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 include, but other functions work well inside in-line code. This is interesting feature if you want to copy some functionality from an existing PHP application. Let's look at the code-behind class now:

<?
  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 partial class here, because ASP.NET generates the second part of the class automatically. The second part of the class contains class members/fields (like lblOutput) for every server control on the page which makes it possible to access them in code-behind. For more examples of using PHP with ASP.NET look at the Personal Web Site StarterKit mentioned earlier.

Other Notes

Mono Support

The 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.

Benchmarks

Because 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 history

The 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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)