We have talked a lot about calling PHP from within C# thanks to Peachpie, but the beauty of this compiler is that the interoperability feature works both ways. In this article, we will take a look at some of the ways you can use C# in PHP.
Introduction
There are more benefits to having your own PHP compiler than just tuning the performance of PHP apps or making use of one language’s syntactic sugars on another platform. Anther benefit worth mentioning is that we can provide incredible interoperability features, i.e. calling functions defined in C# from PHP, and vice versa. Seeing as we have previously discussed how PHP can be used in C#, this post will focus on calling C# methods (or .NET in general) from within PHP.
Motivation
Imagine that you have a performance-critical application or that you would like to gradually migrate your PHP application to .NET. With the feature we are discussing in this article, you can remove a single PHP function or PHP class from your code and implement it in C# or any other .NET language, while the rest of the PHP application can remain untouched. After this process, the application will behave exactly like it did before, except that parts of the code will now be written in C#. You have just seamlessly migrated a small portion of your PHP application to .NET in a completely agile manner, and you can continue to make incremental changes to the codebase as needed.
Another benefit of this process is the .NET platform itself. There is a huge amount of code available in the .NET world, including NuGet packages that you can use freely and seamlessly. Symbols from all the referenced libraries will become available to the PHP code in a smooth and simple manner.
Option One – Referencing Standard .NET DLL
With Peachpie compiler, we are promoting PHP to the world of .NET languages, making its runtime and compile-time compatible with the other .NET languages.
A reference to another .NET project is handled by the compiler and the contained symbols become visible to the PHP code.
In ‘project.json’ we will add references either to another project or to a NuGet package:
[code language=”js”]
"dependencies" : {
"CSharpProject" : "*",
"Json.NET" : "9.0.1"
}
[/code]
Just to demonstrate, this is a source file in a sample `CSharpProject`:
[code language=”csharp”]
namespace A {
class X {
public int foo(string str){ return 123; }
}
}
[/code]
The dependencies above become seamlessly available to the PHP code. The compiler takes care of this process and allows you to use the C# symbols in PHP. Take a look at this sample ‘index.php’ file:
This is the most common use case, where one can use the rich set of libraries available in the .NET world within the PHP code. For the sample project go to https://github.com/iolevel/peachpie-samples/tree/master/using-csharp-from-php and follow the steps in the Readme.
Option Two – Peachpie Specific Library
Since the PHP language has global functions and constants, we had to provide a way of defining such constructs in .NET (which does not have global functions or constants). Therefore, Peachpie provides a special assembly attribute that you can use to mark your project as a PHP library – which is treated differently by the compiler.
[code language=”csharp”]
[assembly: Pchp.Core.PhpExtension]
[/code]
When this attribute is present in a referenced project, all the public static methods of a static class become visible to the PHP code as global functions. Read more about the specs here.
For the full sample of defining a Peachpie library, take a look at:
https://github.com/iolevel/peachpie/tree/master/src/Peachpie.Library
Option Three – Injecting Declarations at Runtime
The most interesting option is to define PHP global functions as C# lambdas dynamically at runtime. You can use a non-existing global function in your PHP code, so the compiler postpones its direct call by using Call Sites. Then, we provide the function definition in the runtime before the call is made so that the runtime uses your provided method. See the following example:
The function foo will be defined later, e.g. as a lambda function. The PHP program will be driven from the C# application:
[code language=”csharp”]
using (var ctx = Pchp.Core.Context.CreateEmpty()) { // this is runtime context for PHP representing a single session or request
// note: following is introduced in Peachpie 0.4
ctx.DeclareFunction("foo", new Func<int, int, string, bool>((a, b, c) => a == b)); // dynamically declares function "foo"
ctx.Include(null, "index.php"); // processes the compiled PHP code which will make a call to foo, try to put a breakpoint into the lambda above
}
[/code]
Open the full up-to-date sample at https://github.com/iolevel/peachpie-samples/tree/master/using-php-from-csharp.
Conclusion
The several options of interoperating between the PHP and .NET worlds described in this article give us flexibility in migrating or optimizing existitng PHP apps. The samples above may bridge the gap between the C# and PHP worlds, despite the fact that they are so diametrically different.