Writing Silverlight applications 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:
- Simple car demo - Click on the car and it will move!
- Helicopter game demo - Click left button to fly up!
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:
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
- [1] XAML Syntax Overview - MSDN Documentation
- [2] Microsoft Expression Blend 2 Free Trial - Microsoft Expression
Published: Friday, 7 December 2007, 5:16 PM
Author: Tomas Petricek
Typos: Send me a pull request!
Tags: phalanger