A Hack to PHP transpiler that attempts to preserve as many types as possible

0.0.1 2019-01-02 10:49 UTC

This package is auto-updated.

Last update: 2021-09-28 05:31:11 UTC


Hack to PHP logo

A proof-of-concept Hack to PHP transpiler, written in PHP

This project uses HHVM's builtin parser (hh_parse) and an existing library to turn Hack code into PHP code. It generates PHP-Parser-equivalent nodes for the original Hack AST, then prints the result.

It aims to preserve all of Hack’s types so that the resultant PHP code can be checked by a tool like Psalm, converting any asynchronous code to its synchronous equivalent.

You can install via composer (composer require --dev hacktophp/hacktophp) and run it like so:

vendor/bin/hacktophp --input=<input-file-or-folder> --output=<output-file-or-folder>

Indefinitely unsupported features

While a lot of code has easy-to-compute PHP equivalents, some builtin Hack constructs are essentially impossible to replicate:


All async/await calls have been made synchronous, converted to promises that use amphp


This valid Hack code

$a = keyset[];
$a[] = "hello";
echo $a["hello"];

transpiles to the valid (but not-equivalent) PHP code

$a = [];
$a[] = "hello";

The only valid option here would be to convert keysets to ArrayObjects, but I'm not sure if that's wise.

Currently unsupported features

  • Pretty much all builtins, but I'm adding things slowly, and HH\Lib\... functions are supported via hacktophp/hsl-php
  • XHP
  • Class constant types e.g.
    class A {
      const type Foo = int;
  • Docblock annotations for Parameterised extends, implements and trait - dependent on Psalm support
  • Docblock annotations for require extends - dependent on future Psalm support
  • User attributes, especially <<Memoize>>
  • types of const (Psalm does a reasonably good job inferring them, but it should be added for completeness)
  • probably many more things I haven't considered