This story is about manipulating or consuming managed assemblies (AKA DLLs) in PHP, mostly (but not only) on Windows systems.
Managed and Un-Managed Code
First I would like to go a little bit further to explain what managed and un-managed code means.
A managed component (which can be an .exe file, an ActiveX control, a DLL and so on) means that it runs under the CLR that .NET provides. Nevertheless, it can execute in other CLR implementations such as Mono.
On the other hand, an un-managed component runs outside the CLR (so outside the control of the virtual machine), it can have access to Win32 APIs and is typically coded in C/C++. The latter are also recognized to have a lower footprint in terms of system resources.
Visual C++ Studio can produce both managed and un-managed code, while Visual C# Studio generates manged code only.
Introducing the DOTNET class
But how comes that you can actually load and consume such a DLL in PHP ? Well, this is because the managed DLLs have a “built in” component called OLE Automation Layer. This is basically a COM subset that expose a set of interfaces so that a DLL can be consumed at run-time without prior compiling knowledge. COM is one of the main methods of gluing components on Windows platform.
PHP interacts with .NET DLLs via the DOTNET class. This one simply instantiates a class available with the DLL so you can call the public methods and properties. There are a couple of things you should consider here:
- you have to have the .NET framework installed on the system you are playing on
- you have to be aware of the DLL structure in order know what class(es) to instantiate and what method(s) to call – more details in a minute
Consuming an existing DLL
At a first look, you need to simply give it a try an load it in PHP with the DOTNET class. Sounds simple enough, right ? However you will quickly find out that DOTNET class loads DLLs from the Global Assembly Cache (GAC) only.
Fortunately for us, we have a command line tool called gacutil.exe that can add DLLs to GAC with the press of a button. If you’re on Windows 7 it should be located under
c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\
c:\Program Files (x86)\Microsoft SDKs\Windows\v6.0A\bin\.
Once you find it out, just run the following command on the console
gacutil.exe -i “\path\to\dll-file.dll”.
The “i” flag tells the program to add it to GAC.
Once the DLL is added to GAC you will need another more detail to make it work from PHP. That is to find the corresponding Public Key Token that was assigned to your DLL. A simple way to find it out is to open Windows Explorer and navigate to “C:\Windows\assembly”.
And this is how you invoke it from PHP:
$phpdotnet = new DOTNET("PhpDotnet, Version=188.8.131.52, Culture=neutral, PublicKeyToken=07a115ce41e79116", "PhpDotnet.HelloWorld"); $phpdotnet->GetTitle();
Attention must be paid at Version tag. You must use the same version number as indicated in GAC. The “PhpDotnet” string, in the second parameter of DOTNET class constructor, indicates the namespace the class is being part of, while the “HelloWorld” string indicates the actual class you want to instantiate.
Each class within the DLL must be instantiated separately.
Let’s do a quick recap: (1) register the DLL to GAC and (2) identify the Public Key Token and Version Number.
When making your own DLL
To prepare your own DLL to be used in PHP or any other applications in fact, you will need 2 additional steps.
1. The first one is to make your DLL “COM visible”.
To do that from Visual Studio, you need to go Project Properties -> Application tab -> click the Assembly Information button -> check the “Make assembly COM-Visibile” checkbox.
2. Then you will have to strongly name your DLL.
To do that in Visual Studio, go to Project Properties -> Signing tab and click the “Sign the assembly” checkbox, select “New” and fill in the opened form, as indicated below.
Once you do these two things and compile your DLL, just stick to the above procedure regarding GAC and you’re done with it.
There are few issues when doing this integration that you might want to consider:
1. Public methods
Just like the PHP manual says, the returned object is an overloaded object which makes PHP unaware of the public methods the object might contain. So, if you var_dump it, you will see nothing but an empty array. That is why the inner DLL class structure mus be known prior to calling it.
Luckily for us there is another tool specialized for this job shipped with the .NET framework called ildasm.exe. It is located next to gacutil.exe under
c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\ or c:\Program Files (x86)\Microsoft SDKs\Windows\v6.0A\bin\.
To load and display the DLL structure simply call “ildasm.exe \path\to\your.dll“.
Another issue is that you cannot pass parameters to a class constructor within a DLL.
3. Data types
Being two different programming language, we have different data types involved. This being said, you will have to make sure the DLL class methods return data types that PHP understands (mostly strings, ints, booleans, etc). In case your methods needs to return an array list or a more complicated structure, you might want to consider JSON for encoding.
Wrapping it up
We’ve found out that PHP offers quite an elegant way to handle .NET specific DLLs. You only need to pay a little attention to “instantiate” them in a proper way. However you might be wondering where this stuff will be needed in your projects, right ? Below are two examples, in fact use cases, that we’ve met with our projects.
Reusing or encapsulating business logic
You may find this approach useful in cases where the business logic is encapsulated in a .NET component but you need to use it from PHP too. Here you just load the DLL class and your good to go as opposed of doing them in PHP again.
WCF webservices authentication
It can also serve as an approach of consuming WCF webservices with WSHttpBinding stack enabled, backed by Windows authentication method. While this kind of service has one or two implementations in PHP, they are difficult to setup which could make the DOTNET class & DLL combo a viable alternative.