Facebook’s Hack for PHP

Hack is Facebook’s extension to PHP that makes it a much nicer language to work with. We’ve been using it at PocketRent since James discovered it and reverse-engineered how to use it from the HHVM source code. Since using it, writing vanilla PHP now feels wrong and like it’s missing this really useful, powerful features.

Facebook has just released the Hack documentation and tools that we have been using on some projects and our Hack-specific library Beatbox.

Enabling Hack

To have a file run in Hack mode, start it with <?hh instead of <?php or use -vEval.EnableHipHopSyntax=true when starting HHVM. If you will be using the type checker on your code, you have to start the file with <?hh. The Eval.EnableHipHopSyntax flag only enabled runtime support of normal PHP files.

Type annotations

One of the major features that Hack introduces is static typing. The closest PHP has to this is what it calls “type hinting” where you can specify the class name, or array for an array, of a function argument you want and PHP will throw a fatal (though ignorable) error if the passed value doesn’t match. Hack extends this behaviour to allow checking against primitive types (int, float, etc) which get checked by HHVM. It also allows you to provide both return types and ivar types. While ivar types are not checked by HHVM, you can enable return type checking by setting the Eval.CheckReturnTypeHints to either 1 (if you want E_WARNING) or 2 (if you want E_RECOVERABLE_ERROR) and the Hack tools check the types on ivars.

class A {
    private int $foo = 0;
    public function setFoo(int $foo): this {
        $this->foo = $foo;
        return $this;
    }

    public function Foo(): int {
        return $this->foo;
    }
}

In this example: the foo ivar has a type of int; the setFoo method takes an int and returns an object that’s an instance of this; and the Foo method returns an int.

Lambdas

While PHP already supports closures, they can be cumbersome for one-liners. For instance, take this contrived call to array_map:

array_map(function(string $arg): string {
    return $arg . '[]';
}, $array);

Compare that to the equivalent but with a lambda expression instead:

array_map((string $arg):string ==> $arg . '[]', $array);

The expression has a list of arguments and the return type on the left and a single statement on the right, the value of which is used as the return value.

Collection Types

PHP has one collection type: a hash map. You get to it by using array and can even use automatic incrementing indexes like an array. However, the underlying structure is still a hash map. While this does have its uses, it also has drawbacks and doesn’t convey semantics very well.

Hack adds in collection types, allowing you to have variables that are actually maps, vectors or sets. There are also immutable versions of each. Much like arrays, there is literal syntax for creating them:

$map = Map {
    'key' => 'value',
};
$immutableVector = ImmVector {
    'value',
    'value',
    'value',
};
$set = Set {
    'value1',
    'value2',
};

The collection types also expose lazy iterators. For instance, you could do something like:

foreach($map->filter((int $a):bool ==> $a > 10)->map((int $a):int ==> -$a) as $var) { 

and the map will only pull out a value as needed from filter, which will only pull out a value as needed from $map. This sort of pattern, which you can use yourself through the provided LazyIterable interface, is more useful when you only want a subset of the entire results and you’re having to calculate each value, perhaps through a generator or API request.

This is just a small sample of the many useful additions Hack provide to PHP. You can find out about some of the other features by reading the HHVM source code and watching talks by people on the HHVM team. For the others, you’ll have to wait for the documentation and tools to be released to learn about them.

PayPal: simon@simon.geek.nz

 

Leave a Reply