PHP with CLR stuff¶
Imagine all the C#/.NET objects were available to the PHP code ... including the entire .NET runtime. Today we'll glance round .NET threading, Tasks, and CLR debugging.
System.Threading.Tasks.Task¶
A task is an object that encapsulates a delegate
, its state and the state of the task itself. Its delegate
is invoked on a "context". C# language lets you to do crazy things with tasks, scheduling them on various contexts, awaiting them asynchronously, and so on.
We won't be doing that in PHP code. We'll "only" create a Task
and we'll run it on a background thread while the main thread will continue executing its code.
The Code¶
We're writing standard .php
file (i.e. main.php
) with the following valid PHP code:
<?php
use System\Threading\Tasks\Task;
use System\Threading\CancellationToken;
use System\Threading\CancellationTokenSource;
First, we introduce some class aliases, so we can then write just short names in our code. Notice, that there is no difference between PHP class or .NET class. It's all the same for the compiler.
Put our code into a global function main
(the name does not matter). The reason is that the compiler works better with local variables - their types can be inferred better and compiled code is much more efficient.
Now create a CancellationTokenSource
object - we'll use to cancel the background task, as we usually do in C# programs.
Here the magic happens; the line above creates a Task
object with a delegate that will be executed on a thread pool, and runs it.
Under the hood, this PHP anonymous function is compiled as a static CLR method with the following signature:
PeachPie runtime creates a Closure
object which wraps delegate to this method together with the use
$token
argument. Then the PeachPie runtime builds in-memory Action
delegate which calls the created Closure
. Finally, the Task::Run(Action, CancellationToken)
static method get invoked.
Inside the anonymous function ({ ... }
) running on a background thread we can do whatever we want to. For exmaple running some computation and periodically check the $token
for cancellation.
After the task is created, we continue execution on the main thread. In this sample, we schedule the CancellationTokenSource
to cancel after 1 second, and wait synchronously for the background Task
$task
to finish.
Disclaimer¶
Some of the features necessary for this code to run - like passing a struct CancellationToken
between closures, calling methods on value types, or better overload resolution - were implemented in pre-release version of PeachPie 1.2.0-r17766
. You'll need to grab PeachPie from sources or get access to our private NuGet feed with all the SDKs, Runtime, and Compiler prepared for you.
Building Code¶
As for any other C#/.NET project to run, we need a project file and dotnet
SDK.
Make sure you have dotnet
(at leats 8.0): https://dotnet.microsoft.com/en-us/download
Add the following project file (i.e. system-threading-tasks.msbuildproj
):
<Project Sdk="Peachpie.NET.Sdk/1.2.0-r17797">
<PropertyGroup>
<OutputType>exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<StartupObject>main.php</StartupObject>
</PropertyGroup>
<ItemGroup>
<Compile Include="**/*.php" />
</ItemGroup>
</Project>
The project file is a standard MSBuild project that specifies
-
Peachpie.NET.Sdk
as its "base" project. It defines how to call the compiler, it embeds the compiler binaries themselves, and it defines default compilation options.dotnet
will get it from NuGet feed. -
<OutputType>exe</OutputType>
tells the compiler we're building executable console app. -
<TargetFramework>net8.0</TargetFramework>
is our target ramework, in this case .NET 8.0. -
<Compile Include="**/*.php" />
selects all.php
files in project folder as source files. They will be compiled into the resulting .NET assembly.
Once you have the project file (.msbuildproj
) and source file(s) (.php
), run the build:
and/or run the program:
Project¶
The complete project can be found on https://github.com/iolevel/peachpie-samples/tree/patreon/system-threading-tasks
You can open it in Visual Studio Code, Visual Studio (at least 2022), or Rider. In those IDE's you can click on Run/Debug
and even place breakpoints and debug the code in CLR style.