New Release – PeachPie 0.9.38

In preparation for the stable release of PeachPie 1.0, we are cleaning up the code and conducting some final fixes and enhancements.

New Features

In the latest release, the PeachPie platform has received several new features, fixes and improvements in compatibility with the standard PHP framework.

  • New diagnostics: when compiling your code, you probably get a bunch of warnings and possibly some errors, which means that the code is not in perfect shape in the eyes of the compiler. You might find out about typos, forgotten variables or other kinds of minor mistakes, based on our code flow and type analysis. For a list of common diagnostics, see https://docs.peachpie.io/php/diagnostics/. Here’s a few examples of newly implemented ones:
    • PHP4052: Cannot re-assign $this
    • PHP5016: Assert always fails
    • PHP5018: The function has been deprecated
    • PHP5029: Method __tostring() must return a string value
  • MySQL 8.0 Client: updated dependencies, finally allowing you to connect to the newest MySQL servers using secure connections. Additionally, all the other database client libraries were updated.
  • Added/fixed standard PHP functions: fgets(), json_encode(), defined(), PDO’s FETCH_UNIQUE and many more functions have been fixed or implemented. Also, the compatibility with PHP’s
    standard PCRE has been improved.
  • Compiler enhancements: fewer crashes during the compilation and more information about not-yet-implemented functionalities. Also, the compile speed and code analysis have been improved.

Performance

Performance is of course a major topic when it comes to compilers in general. Well-written code can drastically improve performance. We recommend using Visual Studio’s diagnostics and profiler to find bottlenecks in your code. Otherwise the compiler tries to do its best to optimize the code. As of version 0.9.38, the compiler performs the following:

  • expression evaluation, well-known function call evaluation
  • control flow analysis, intraprocedural type analysis
  • unreachable code elimination
  • direct function/method call

This and other features of the compiler may result in clean CIL byte code, possibly equivalent to what you’d write in strongly typed languages like C#.

For a quick comparison we can take a look at a simple algorithm written in PHP – a Leibnitz function for computing Pi.

function pi_leibnitz(int $accuracy) {
 $pi = 4.0; $top = 4.0; $bot = 3; $minus = TRUE;
 for ($i = 0; $i ≤ $accuracy; $i++)  {
  $pi += ( $minus ? -($top/$bot) : ($top/$bot) );
  $minus = ( $minus ? FALSE : TRUE); 
  $bot += 2;
 }
 return $pi;
}
pi_leibnitz( 10000000 );

The resulting CIL byte code of the function “pi_leibnitz” above would be the following (disclaimer – may change with every update of the compiler):


.method public static 
    float64 pi_leibnitz (
        class [Peachpie.Runtime]Pchp.Core.Context <'ctx'>;,
        int64 accuracy
    ) cil managed 
{
    // Method begins at RVA 0x2154
    // Code size 112 (0x70)
    .maxstack 3
    .locals init (
        [0] float64,
        [1] float64,
        [2] valuetype [Peachpie.Runtime]Pchp.Core.PhpNumber,
        [3] bool,
        [4] int64
    )

    // PhpNumber bot = PhpNumber.Default;
    IL_0000: ldsfld valuetype [Peachpie.Runtime]Pchp.Core.PhpNumber [Peachpie.Runtime]Pchp.Core.PhpNumber::Default
    IL_0005: stloc.2
    // (no C# code)
    IL_0006: nop
    // double pi = 4.0;
    IL_0007: ldc.r8 4
    IL_0010: stloc.0
    // (no C# code)
    IL_0011: nop
    // double top = 4.0;
    IL_0012: ldc.r8 4
    IL_001b: stloc.1
    // (no C# code)
    IL_001c: nop
    // bot = PhpNumber.op_Implicit(3L);
    IL_001d: ldc.i4.3
    IL_001e: conv.i8
    IL_001f: call valuetype [Peachpie.Runtime]Pchp.Core.PhpNumber [Peachpie.Runtime]Pchp.Core.PhpNumber::op_Implicit(int64)
    IL_0024: stloc.2
    // (no C# code)
    IL_0025: nop
    // bool minus = true;
    IL_0026: ldc.i4.1
    IL_0027: stloc.3
    // (no C# code)
    IL_0028: nop
    // long i = 0L;
    IL_0029: ldc.i4.0
    IL_002a: conv.i8
    IL_002b: stloc.s 4
    // loop start (head: IL_002d)
        // (no C# code)
        IL_002d: nop
        // if (i < accurancy)
        IL_002e: ldloc.s 4
        IL_0030: ldarg.1
        IL_0031: clt
        // while (true)
        IL_0033: brfalse.s IL_006c

        // (no C# code)
        IL_0035: nop
        IL_0036: nop
        // pi += (minus ? (0.0 - top / bot.ToDouble()) : (top / bot.ToDouble()));
        IL_0037: ldloc.0
        IL_0038: ldloc.3
        IL_0039: brtrue.s IL_0046

        IL_003b: ldloc.1
        IL_003c: ldloca.s 2
        IL_003e: call instance float64 [Peachpie.Runtime]Pchp.Core.PhpNumber::ToDouble()
        IL_0043: div
        // (no C# code)
        IL_0044: br.s IL_0050

        IL_0046: ldloc.1
        IL_0047: ldloca.s 2
        IL_0049: call instance float64 [Peachpie.Runtime]Pchp.Core.PhpNumber::ToDouble()
        IL_004e: div
        IL_004f: neg

        IL_0050: add
        IL_0051: stloc.0
        // minus = !minus;
        IL_0052: ldloc.3
        IL_0053: ldc.i4.0
        IL_0054: ceq
        IL_0056: stloc.3
        // (no C# code)
        IL_0057: nop
        // bot += 2L;
        IL_0058: ldloc.2
        IL_0059: ldc.i4.2
        IL_005a: conv.i8
        IL_005b: call valuetype [Peachpie.Runtime]Pchp.Core.PhpNumber [Peachpie.Runtime]Pchp.Core.PhpNumber::op_Addition(valuetype [Peachpie.Runtime]Pchp.Core.PhpNumber, int64)
        IL_0060: stloc.2
        // (no C# code)
        IL_0061: nop
        IL_0062: nop
        // i++;
        IL_0063: ldloc.s 4
        IL_0065: ldc.i4.1
        IL_0066: conv.i8
        IL_0067: add
        IL_0068: stloc.s 4
        // (no C# code)
        IL_006a: br.s IL_002d
    // end loop

    IL_006c: nop
    // return pi;
    IL_006d: ldloc.0
    // (no C# code)
    IL_006e: nop
    IL_006f: ret
} // end of method program_php::pi_leibnitz


Always fun to mess around with IL, isn’t it? In the comments you can see the CIL “decompiled” to C#, which gives you an idea of what’s going on. What’s great about this approach is that this byte code is later compiled again by the .NET runtime into the actual machine code of your particular CPU. I’m not going to post the assembler in here.

But what about the performance results? If we run the same code using PHP 7.2, PHP 7.3 and .NET Core 2.0, we get quite a huge difference:

PHP 7.2… 1.141s
PHP 7.3… 0.817s
PeachPie 0.9.38 + .NET Core 2.0… 0.283s

First, we can see PHP’s performance getting better and better. However, the compiled code on .NET Core is about 3 times as fast. A few notes here:

  • The test machine is a Thinkpad X260, Core 7-i7-6500U, 8GB DDR4.
  • PeachPie is still in development and a majority of the possible optimizations have not yet been implemented. We haven’t even properly profiled yet.
  • For now, real-world scenarios and applications on PeachPie (e.g. running WordPress or MediaWiki) are roughly the same speed as in PHP.
<Project Sdk="Peachpie.NET.Sdk/0.9.38">
  <PropertyGroup>
    <OutputType>library</OutputType>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Compile Include="**/*.php" />
  </ItemGroup>

</Project>

How to use this

The main message when using PeachPie is that you would treat PHP code as if it were a .NET project (C# project). This means that your files need to be in a folder, and there has to be a project file. In general, refer to our getting started or our samples GitHub repository. The project file describes what files will be compiled, what diagnostics are ignored, what .NET framework you are targeting and if you are building a console application or a library that can be referenced by other .NET projects or loaded into the web server.

1/ Start with an empty folder and create a file project.msbuildproj, initialize it with the following content (details on 
https://docs.peachpie.io/php/msbuild/):

2/ Copy some PHP files in the folder; you can start with a hello world program.php:

<?php

echo "Hello World!";

3/ That’s it. Start the program. You can either compile it and distribute your binaries or just run it. Note that .NET downloads dependencies and compiles the program on the first run.

> dotnet run

Other usages are:

  • dotnet run -c release # compiles and runs the program in release mode
  • dotnet pack # creates a distributable NuGet package with your code
  • dotnet build # just compiles the code, so you can check the diagnostics

There’s much more you can do with PHP code compiled and transferred to the .NET platform. Once again, see our samples GitHub repository with a web application, a library or interoperability calls between C# and PHP to find out more.

So what’s next?

We are putting the finishing touches on our cleanup and maintenance prior to releasing version 1.0 of PeachPie. Once this release will be out, we’ll likely reduce the number of official releases, but you can always grab the latest dev version from AppVeyor. 

We’ve made great strides extending the suite of compatible PHP apps and frameworks as well, working on Symfony, Laravel or Drupal for example. We still have some work ahead of us before PeachPie will be compatible with these projects, but we’re getting there. 

Unrelated to our work, we’re also very excited for the release of .NET Core 3.0, which promises to bring even greater performance enhancements. We’ll be sure to focus on optimizing the way we compile and run code going forward and in combination with Microsoft’s efforts, we are optimistic about where we can take the performance of PHP applications in the future.

Share this article:Share on FacebookShare on VKPin on PinterestShare on Google+Tweet about this on TwitterShare on LinkedInShare on Reddit
Posted on April 1, 2019, in category Announcement, Benchmark, Information, News, tags: , , , , , ,