Skip to content
Timm Friebe edited this page Mar 23, 2024 · 41 revisions

What is XP Compiler?

XP Compiler compiles future PHP to today's PHP. Kind of like the Babel of the PHP world.

It supports a large set of Hack, PHP 8.3, PHP 8.2, PHP 8.1 and PHP 8.0 but runs on anything >= PHP 7.4. Builtin features from newer PHP versions are translated to work with the currently executing runtime if necessary.

XP Compiler can be used in two ways: First of all, there is a command line tool, xp compile. Second, it plugs into the class loading mechanism and compiles code just in time - providing a seamless experience of writing code, saving, and running PHP.

Features

Some features from newer PHP versions as well as Hack language are still missing. The goal, however, is to have all features implemented - with the exception of where Hack's direction conflicts with PHP! An overview can be seen on this Wiki page.

Table of contents
Types Operators
Annotations Trailing commas
Arrow functions Anonymous classes
Compact functions New dereferencing without braces
Constructor argument promotion Multiple catches
Using statement Constant modifiers
Null-safe instance operator Short list syntax
Unicode escapes Splat operator in arrays
Throw expressions Casting

Types

We allow you to express types more concisely. On top of primitives, void, arrays, callables, iterables, objects and value types supported in today's PHP it allows nullable, function and union types, mixed, as well as array and map types:

function cookies(string $header): array<Cookie> {
  // …
}

On top of this, property type hints are supported:

class Person {
  private string $name;
}

Explore the type system.


Annotations

One of the most requested PHP features are annotations - or attributes. XP Compiler supports them using PHP 8 attributes syntax:

use unittest\Test;

class FixtureTest {

  #[Test]
  public function can_create() {
    new Fixture();
  }
}

Continue reading the overview of supported annotation features


Arrow functions

Using arrow notation, you can shorten closures:

$mul= function($a, $b) { return $a * $b; }
$mul= fn($a, $b) => $a * $b;

All details on arrow functions can be found here.


Compact functions

Because the => operator essentially stands for omit braces and return, it will also work in function and method declarations:

class Person {
  private string $name;
  public fn name(): string => $this->name;
}

This feature is unique to the XP Compiler (not found in PHP or Hack Language) and is described in the XP Compact functions RFC. See also C#'s Expression-bodied members.


Constructor argument promotion

Another way to shorten your code is to use constructor argument promotion. It replaces the declaration of a member and its initialization via the constructor with a single keyword:

class Connection {
  public function __construct(private URL $url) { }
  public fn url() => $this->url;
}

This feature comes from Hack language


Using statement

Another HHVM / Hack feature supported by XP Compiler is the using statement. You might know this from C#, or as "try with resources" from Java. It integrates with both the Disposabe interface as well as XP's lang.Closeable.

using ($c= new Connection($url)) {
  …
} // $c->close() called automatically

See Using statement / Disposables for details.


Null-safe instance operator

Null handling can be tedious. XP Compiler supports the ?-> operator, which accesses instance members like ->, but only if the expression on the left-hand side is not null.

$name= $list->first()?->name() ?? '(no name)';

See also the Null-safe instance operator documentation.


Trailing commas

Trailing commas are allowed in all places PHP 7.3+ supports them:

  • Arrays and maps - this has worked in PHP for a long time
  • Function calls - $f(1, 2, ), see this RFC
  • Grouped use statements - use lang\{Value, CommandLine, }, see here

Anonymous classes

This PHP feature is supported natively in all PHP 7 versions:

$instance= new class() implements Runnable {
  public function run() { … }
};

See https://wiki.php.net/rfc/anonymous_classes


New dereferencing without braces

Because of the way the XP Compiler is implemented, dereferencing from an instance creation expression can be done without the need to put it inside braces:

$string= new Date()->toString();

Of course, surrounding it with braces also works!


Multiple catches

Sometimes, it is necessary to handle unrelated exceptions in the same manner:

try {
  // ...
} catch (IllegalArgumentException | FormatException $e) {
  $log->warn($e);
  // ...
}

This PHP 7.1 feature is simulated on PHP 7.0. In addition, XP compiler also supports omitting the types in order to catch all exceptions (try { … } catch ($e) { … }).


Constant modifiers

Class constants can have a public, private or protected modifier since PHP 7.1:

class FixtureTest extends TestCase {
  private const SERVER = 'http://test.url/';

  // ...
}

See https://wiki.php.net/rfc/class_const_visibility


Short list syntax

Consistent with short array syntax, you can now also use a shorter form of list():

[$localpart, $domain]= explode('@', $mail);

This was introduced in PHP 7.1 and will be rewritten in older PHP versions.


Throw expressions

With XP Compiler, throw can be used inside ternary (?:) and null-coalesce (??) operators as well as inside lambda expressions and compact function syntax.

$command= $args ? $args[0] : throw new IllegalArgumentException('Argument expected');

class Test {
  public fn invoke() => throw new MethodNotImplementedException(__METHOD__);
}

This feature is unique to XP Compiler and neither present in PHP nor HHVM. It is inspired by C# 7.0 and an open JavaScript proposal, as well as Kotlin.


Splat operator in arrays

Instead of having to write array_merge(), the XP Compiler will allow using the ... operator inside arrays:

$commandLine= ['xp', Splat::class, ...$args];

// same as:
$commandLine= array_merge(['xp', Splat::class], $args);

This feature was drafted as a PHP RFC at https://wiki.php.net/rfc/additional-splat-usage


Casting

All types in the type system can also be cast to. The following all also work in PHP:

$i= (int)"123";     // 123
$s= (string)$name;  // string, invokes __toString() if object, coerces otherwise
$a= (array)$value;  // array, objects' properties, an empty array for NULL, [$value]

On top of this, XP Compiler supports value type casts:

$h= (Handle)$h;     // invokes cast($h, Handle::class)

Also, casting to nullable types work out of the box:

$i= (?int)null;     // null
$h= (?Handle)$h;    // null or an instance of Handle