Syntactic Sugar with a PHP Compiler

With each new release of our PHP to .NET compiler, we implement more and more PHP syntax. This week, we would like to demonstrate some of the nifty features of PHP.

Extended Methods Overriding and Default Values

Most of the compiled PHP syntax results in .NET C#-like constructs. Since PHP is more flexible than C# and allows developers to achieve complex constructs with less code, the compiler has to generate code in order to build CLI compliant assemblies.

In .NET and PHP, developers can override a base method with a new implementation. However, PHP allows to extend the base declaration with additional parameters. Also, in PHP you can specify a default parameter value other than a simple literal, like a new array initialized with constant values.

You can neither do that in C# nor in .NET itself, so Peachpie generates so called ghost stubs to build something that is compatible with both .NET and PHP. Since the compiler builds something for you, allowing you to do more with less code, we call it syntactic sugar. Let’s take a look at an example.

Notice that the method B::foo overrides A::foo implicitly. However, their signature does not match as it is required in .NET. Peachpie PHP compiler handles this situation and generates a .NET assembly with additional stubs. After decompiling it into C# (e.g. using the ILSpy tool) you can see something like the code below.

public class A {
    public virtual PhpValue foo() {
        this.<ctx>.Echo(123L);
        return PhpValue.Void;
    }
}
public class B : A {
    public virtual PhpValue foo(PhpValue one, PhpValue another) {
        base.foo();
        Variables.var_dump(this.<ctx>, new PhpValue[] {
            one,
            another
        });
        return PhpValue.Void;
    }

    public PhpValue foo(PhpValue one) {
        PhpArray expr_08 = new PhpArray(3){PhpValue.Create(1L), PhpValue.Create(2L), PhpValue.Create(3L)};
        return this.foo(one, PhpValue.Create(expr_08));
    }

    public sealed override PhpValue foo() {
        PhpArray expr_0C = new PhpArray(3){PhpValue.Create(1L), PhpValue.Create(2L), PhpValue.Create(3L)};
        return this.foo(PhpValue.Void, PhpValue.Create(expr_0C));
    }
}

The compiler generates additional stubs that define the correct .NET override for two reasons:

  • In order to override foo(), the signatures have to match, so the new override is defined as sealed and the compiler introduces a new virtual method foo($one, $another).
  • Since an array is not a supported default .NET value, the compiler has to create a stub with fewer parameters calling the full implementation with the default values constructed in the runtime.

Array Initialization

Another syntactic sugar is the array initialization itself. The following two samples perform the same action after the compilation.

$arr = [1, 2, 3, "Hello"]
var arr = new List<Object>(4){ 1, 2, 3, "Hello" };

The List <object> is closest to the PHP array implementation in .NET. Notice how Peachpie internally defines its own collection object with PHP semantics.

Conclusion

Writing code in PHP while compiling it to .NET is not only a migration tool or a performance optimization process. As you can see above, new code can also be written in PHP to achieve a smaller, more compact code base and faster development while being compatible with .NET platform.

Posted on November 29, 2016, in category Information, tags: , , , ,