PeachPie Update – May

We stepped on the gas lately and implemented hundreds of little changes and features in the PeachPie platform gearing up for its 1.0 release. What’s new?

Once we got the essentials working, we focused on supporting a wider range of applications and libraries. WordPress already works pretty nicely, including hundreds of its plugins and themes, so what else was missing?

Yield & Generators

PHP allows for yield the same way as we know it from C#; but there is more. In addition to C# (or CLR actually), one can “yield” from try/catch/finally blocks. This feature was not supported by PeachPie since it was limited by the CLR. Not anymore.

PeachPie compiler now generates a state machine around “try” blocks, and in case of “catch” and “finally”, it compiles them out of the “TryCatchFinally” scope. This allows for the generator method (Enumerator in C#) to have yields anywhere, and so the following sample can finally be translated to CIL:

function g() {
  try {
    yield "I'm in try";
  }
  finally {
    yield "I'm in finally";
  }
}

You can enjoy the beauty of the compiled code, decompiled to C# here:

[return: NotNull]
public static Generator g(Context ) {
     return Operators.BuildGenerator(, new PhpArray(), new PhpArray(), new GeneratorStateMachineDelegate(index_php.<>sm_g), methodof(index_php.g(Context)).MethodHandle);
}
private static void <>sm_g(Context , object @this, PhpArray , PhpArray , Generator generator) {
     int generatorState = Operators.GetGeneratorState(generator);
     Operators.SetGeneratorState(generator, -1);
     int num;
     if (generatorState == 1 || generatorState != 2)     {
         try         {
             if (generatorState != 1)            {
                 Operators.SetGeneratorCurrent(generator, "I'm in try");
                 Operators.SetGeneratorState(generator, 1);
                 return;
             }
             Operators.HandleGeneratorException(generator);
         }
         catch (ScriptDiedException) {
             // special exception intended to terminate the script 
             // throws in response to eit or die
             throw;
         }
         catch (Exception arg_46_0) {
             <tmpLocals>.SetItemValue(new IntStringKey("<>1"), arg_46_0);
             num = 2;
             <tmpLocals> .SetItemValue(new IntStringKey("<>0"), num);
         }
         Operators.SetGeneratorCurrent(generator, "I'm in finally");
         Operators.SetGeneratorState(generator, 2);
         return;
     }
     Operators.HandleGeneratorException(generator);
     num = (int) <tmpLocals> .GetItemValue(new IntStringKey("<>0"));
     if (num == 0) {
         Operators.SetGeneratorState(generator, -2);
         return;
     }
     if (num != 1) {
         // rethrow exception from "catch" block
         // we have to use .throw operation
         // since .rethrow is limited to TryCatchFinally scopes only
         throw (Exception)<tmpLocals>.GetItemValue(new IntStringKey("<>1"));
     }
}

Return from finally

The same applies to returning a value from a “finally” block. You cannot do that on the CLR, but in PHP it is allowed. This is also handled by compiler using the same method as for yield above. A temporary variable for the returned value is created, finally compiled outside the TryCatchFinally scope, and return is actually performed after the finally block. This allows us to “override” the returned value! Let’s see the sample below:

function f() {
  try {
    return 1;
  }
  finally {
    return 2;
  }
}

Resulting in something equivalent to the following:

public static long f() {
     long _r;
     try {
       _r = 1;
     }
     catch (ScriptDiedException)
     {
         throw;
     }
     catch (Exception arg_0A_0)
     {
     }
     _r = 2;
     return _r;
 }

Composer.json

The build process now peeks into the composer.json file. It is a natural part of most PHP libraries and projects, providing useful meta information. One example is a list of dependencies, which can now be used (i.e. a reference to pdo_mysql which gets translated implicitly to a corresponding <PackageReference />).

See our docs at docs.peachpie.io/php/composer-json/.

Sockets

PHP has a bunch of extensions that are somehow corresponding to the BCL of .NET. Sockets is one of them, a standard library that was not implemented in PeachPie until now. There are a few functions still missing from the “sockets” extension, but they are not used in the projects we’ve come across so far. See our compatibility page for the current status at docs.peachpie.io/compatibility-status/.

PDO

This extension provides an abstraction over database connections and queries. There are a lot of small features and specific behavior to be implemented, but we are progressing fast. Mostly thanks to our community reporting all these small nuances between .NET and PHP. PDO in PeachPie now understands the conventional named parameters in query strings, more common attributes etc. It is a great example of abstracting various database providers under a single API. .NET has a similar approach with System.Data.Common.DbProviderFactory, DbConnection, DbCommand, and others, which PeachPie is built on.

PCRE

Pear Regular Expressions (or PCRE) is a well-known set of APIs with nicely documented syntax. In addition to C# Regex, it provides recursion, and more syntactic features. The final PHP function – preg_filter - has been implemented and thus our support for PCRE is now complete.

FTP

Another extension we recently implemented. Ftp standard library is now a part of PeachPie, fully implemented on managed .NET.

Fixing issues

We are very happy for all the issues reported, all the code samples, and test cases. Thanks to the community on GitHub and Gitter, we have been able to fix (or implement?) hundreds small features to make the behavior on .NET and PHP almost the same, allowing to run regular PHP projects on .NET. Check our GitHub for more details! github.com/peachpiecompiler/peachpie/

Posted on May 17, 2020, in category Information, News, tags: , , , , , , , ,