TP

Writing Silverlight applications in PHP

Simple Silverlight App in PHP

In my last post about Phalanger I mentioned that our important goal is to support the Silverlight (2.0) platform. Shortly Silverlight is a cross-browser platform that can be used for developing client-side components that run in the web browser and contain rich media, graphics and can interactively communicate with the user. The language that can be used for writing Silverlight code can be in general any .NET language, so our goal is to allow using PHP by making Phalanger compatible with Silverlight.

First steps were already made and it is becoming possible to write some very interesting things in Silverlight using PHP, there is of course still a lot of work to do and we're discussing the future development with PHP development team (you can join the mailing list PHP on DLR for more info). In this article we will first show a very basic Silverlight example that uses PHP and later I will shortly comment more complicated example - a game (quite addicting, so be careful :-)!) where you have to fly with helicopter and avoid the walls. The source code for helicopter game is also attached, so feel free to modify it or create similar games!

If you can't wait to try the demos before looking at the sources, here are the links:

Introducing PHP for Silverlight

An inevitable part of almost any Silverlight application is XAML file. XAML is a declarative language based on XML (which is in some ways similar to SVG) and is used for describing the user interface elements of the application - it is important to note that these elements are all represented by some object at runtime and so the XAML actually just creates instances of these objects. XAML can be used for defining basic graphical elements like shapes (Ellipse, Rectangle, ...), elements that can be used for grouping other elements (Canvas), but also animations. Animations are quite interesting, because they specify how properties of other object (specified using Name) should change when the animation runs. For example you can create an animation in XAML that moves object from position [0, 0] to [100, 100] in 100 seconds.

XAML Source File

The following XAML sample contains part of the declarative markup used to create the car that you can see in the screenshot above. The live version of the example can be found here. The sample application contains an HTML file with some JavaScript that initializes the Silverlight component (you can download them below and analyze them yourself). When the Silverlight component is initialized the XAML file is loaded and this is where the Silverlight application starts executing. Let's now look at the structure of simplegui.xaml file:

<Canvas x:Name="parentCanvas"
    xmlns="http://schemas.microsoft.com/client/2007" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:php="clr-namespace:PHP.Silverlight;assembly=ClientBin/PhpNetCore.dll"
    Width="800" Height="600" Background="White" >
  <!-- Specifies the PHP code that drives the application -->
  <php:PhalangerLoader Source="Simplegui.phpx" />

  <Canvas.Resources>
    <!-- Animation that moves the car object -->
    <Storyboard x:Name="moveCar">
      <DoubleAnimation From="0" To="810" Duration="0:0:2" 
                       Storyboard.TargetName="carCanvas" 
                       Storyboard.TargetProperty="(Canvas.Left)"/>
    </Storyboard>
    <!-- (...) more animations -->
  </Canvas.Resources>

  <!-- Car - composed from ellipses and rectangles -->
  <Canvas x:Name="carCanvas">
    <!-- Back wheel -->
    <Ellipse x:Name="wheel1" Width="47" Height="47" Stroke="#FF000000" 
             Canvas.Left="5" Canvas.Top="228" />
    <!-- (...) other car parts -->
  </Canvas>  
</Canvas>

There are a few important things to note. First, the whole content is contained in a Canvas element, which is a container for other elements. The root element contains several standard xmlns declarations and also xmlns:php="...", which imports element that will be later used to load PHP code. In the XML namespace declaration we have to specify the path to the Phalanger Core assembly (called PhpNetCore.dll). Later, the php:PhalangerLoader element is used to specify what PHP source file is attached to the application - this will be in more details discussed shortly.

Other interesting element in the file is Canvas.Resources. This element specifies resources of the root canvas and in our example contains animation declarations. The animation is created using Storyboard element, which we will later retrieve from the resources using the Name attribute and start from our PHP code. The storyboard can contain several animations that specify how some attribute of other object should change - in this example we have a single DoubleAnimation, which linearly animates a floating point value from 0 to 810. The property that will be changed during the animation is Canvas.Left (the position of the shape from left relatively to the parent Canvas object) and the animated object is an object with name carCanvas. Finally, the last attribute (Duration) specifies that the animation should take 2 seconds.

Explaining everything that can be done just in XAML would make quite a long article alone, so I will not go in further details in this article, though I will definitely mention a few more things in the future. Good reference with examples can be found in the MSDN Documentation for Silverlight [1]. Also, it is possible to create XAML files in a graphical designer called Expression Blend 2 [2], which is currently available as a beta version. It doesn't directly support PHP projects, but you can use it to create XAML files that can be later copied to your Phalanger-powered Silverlight applications.

PHPX Source File

In this example, I use phpx as an extension for the client-side PHP code that will run in Silverlight. As you can see the file is referenced using file name from the XAML file and this also means that the source code is downloaded from the server to the client and executed there. To make this possible the extension of client-side (Silverlight) PHP code has to be an extension that the web server will serve as a plain text (as an opposite to server-side PHP code which is executed by the web server). If your web hosting doesn't allow hosting of files with phpx extension you can use for example txt and it will also work.

Let's now look at the PHP code file that controls the demo with a car (available here). The PHP file contains code that defines the interaction for our application, which is in this example very simple - when a user clicks on the car we want to start the animation:

<?
import namespace System:::Windows:::Input;
// Include common Silverlight utilities
include("slutils.phpx");

// Initialize canvas wrapper for working with the XAML elements
global $CANVAS;
global $cv;
$cv = new CanvasWrapper($CANVAS);

// Called when user clicks on the car
function OnClick() {
  global $cv;
  // Start the animation declared in XAML
  $cv->moveCar->Begin();
}

// Called when the Silverlight component loads in browser
function OnLoad() {
  global $cv;
  // Attach the event handler for 'MouseLeftButtonDown' of the 'carCanvas'
  $cv->carCanvas->MouseLeftButtonDown->Add
    (new MouseEventHandler("OnClick"));
}
?>

On the first line, you can see the import namespace statement, which imports objects from the specified .NET (Silverlight) namespace. This is a non-standard extension to the PHP language which is available in Phalanger to support namespaces (in the future the syntax will be same as syntax for working with namespaces in PHP 5.3). The second line includes a source file with various utilities that make developing Silverlight applications in PHP a lot easier - we will use only a single extension in this example, so I'll comment that shortly below.

The next few lines use a global variable $CANVAS, which is a special variable initialized by the Silverlight module in Phalanger. This variable refers to an object that represents the root canvas object created in XAML and it can be used for manipulating with other named elements in the XAML file (named elements have the x:Name attribute). The variable $cv will be initialized to an object CanvasWrapper, which comes from the slutils.phpx file that I mentioned earlier. This class is a wrapper written in PHP that simplifies the access to the canvas elements - it is working with the .NET representation of the canvas object, which has all the needed functionality, but the wrapper exposes this functionality in a more PHP-friendly style. If you look at the OnClick method (which will be called by the system when user clicks on the car element) you can see a code that starts the animation, by calling Begin method of the Storyboard element declared in XAML. The following example demonstrates how the CanvasWrapper simplifies the code:

// Using CanvasWrapper we can just access 
// 'moveCar' as a member using magical '__get'
$cv->moveCar->Begin();

// Without CanvasWrapper the element has to 
// be accessed using 'FindName' method
$cv->FindName("moveCar")->Begin();

There are of course some other tricks that the slutils.phpx implements, but this is the only one that we needed in this example. The implementation of OnClick function is quite simple, so let's look at the remaining OnLoad function now. The function is called by Phalanger when the Silverlight component is loaded, so we use it here to register an event handler that will be called when user clicks on the car.

To do this, we first access the carCanvas element from the XAML file and we'll use its MouseLeftButtonDown property, which represents the event. Events are general .NET concept and can be used thanks to Phalanger, which understands events and knows how to use them. To register a new event handler that will be called when the event occurs, we use the Add method and give it a corresponding event handler object as an argument. In this case we're working with mouse-related events, so we have to create MouseEventHandler object (which comes from the System:::Windows:::Input namespace). When creating the event handler you can give it either a reference to a global function (as a string) or a reference to a member function, in which case you would give it the following argument: array($this, "FuncName").

Deployment

The last thing that I wanted to comment in this article is the deployment process - that is what you need to upload to your web server when you want to host Silverlight applications in PHP. The Silverlight plugin is installed on the client-side, so you can host it on any server using any server-side technology (both IIS and Apache are fine and you don't even need PHP on the server). The client-side Silverlight application consists of xaml file, phpx file and html with js files that contain the hosted Silverlight control. The JavaScript code that initializes the control can be just copied from any other Silverlight application, so you just need to modify the html and js files to load the correct xaml file (or replace them with more complex server-side code, for example in PHP).

The phpx file has to be published as a text file, so that the source code can be downloaded to the client and compiled and executed there. You can however change the extension (for example to txt) if your web hosting doesn't allow phpx extension. You should be aware of the fact that the source code of the client-side part of your application is available to the users and you shouldn't put any security critical information in this file. This is a by-design limitation, because even if we allowed serving the client-side functionality in a compiled file it would be still possible to decompile the source code relatively easily. I will comment the security more in one of the future articles, where we get to sending data from client-side (PHP running in the Silverlight) to the server-side (standard PHP application running on the server).

Finally, the Silverlight has to be installed on the client and you need to upload Phalanger core libraries that will execute the phpx file on the client. Currently, the two files are PhpNetCore.dll and PhpNetClassLibrary.dll - the first one contains the PHP compiler and core runtime and the second one implements common PHP functions. These files have to be in same directory and the PhpNetCore.dll have to be referenced from the xaml file (default and recommended location for both of them is ClientBin subdirectory). I believe that these two files are cached by the browser when they are downloaded, but we still want to make them as small as possible, so expect that the files together will be smaller than 1MB in a near future (in a far feature we'd like to leverage of some DLR capabilities, so the files should get even smaller).

Helicopter Game

So far, we have looked at very simple example where we used XAML to define the user interface elements and animations declaratively and we've used the PHP language (thanks to the Phalanger compiler and runtime) to implement interaction logic for the sample Silverlight application. I will write more about using PHP with Silverlight in the future (let me know if there is some topic that you're in particular interested!), but I also wanted to publish some more complex, so you have a more sample code to look at if you want to play with PHP in Silverlight:

Go to the helicopter game
Go to the helicopter game

The helicopter game uses the concepts introduced in this article (event handlers and the CanvasWrapper object). The rest of the code uses standard PHP programming practices, so it should look quite familiar to any PHP programmer. I believe that this article gives you a good introduction to writing client-side Silverlight applications in PHP!

Downloads & References

Published: Friday, 7 December 2007, 5:16 PM
Author: Tomas Petricek
Typos: Send me a pull request!
Tags: phalanger