Slide 1

Slide 1 text

HHVM + HACK A quick introduction

Slide 2

Slide 2 text

HHVM • Stands for HipHop Virtual Machine • Executes scripts written in PHP (5.4) and Hack • Drop-in replacement for php-fpm • Use together with FastCGI-enabled webserver (like Apache or nginx)

Slide 3

Slide 3 text

Timeline • 2008: Facebook begins work on HipHop, a PHP to C++ compiler • 2010: Facebook opensources the compiler (HPHPc) and dev interpreter/ debugger (HPHPi and HPHPd) • 2010: Facebook begins work on HHVM • 2013: HPHPc deprecated, replaced by HHVM in Facebook production servers • 2013: HHVM 2.3.0 adds FastCGI support • 2014: HHVM 3.0.0 adds Hack support

Slide 4

Slide 4 text

Installation • Ubuntu add-apt-repository -y ppa:mapnik/boost! wget -O - http://dl.hhvm.com/conf/hhvm.gpg.key | sudo apt-key add -! echo "deb http://dl.hhvm.com/ubuntu precise main" > /etc/apt/sources.list.d/hhvm.list! apt-get update! apt-get install hhvm! • Note: there is no more hhvm-fastcgi package. For the latest code, you can use hhvm-nightly • https://github.com/facebook/hhvm/wiki/Prebuilt-Packages-on- Ubuntu-12.04

Slide 5

Slide 5 text

Installation • OSX (using Homebrew) brew tap homebrew/dupes! brew tap homebrew/versions! brew tap mcuadros/homebrew-hhvm! brew install hhvm --HEAD! • https://github.com/facebook/hhvm/wiki/Building-and- installing-HHVM-on-OSX-10.9 • Unfortunately, the typechecker (hh_server / hh_client) does not build on OSX

Slide 6

Slide 6 text

Installation • Windows • … just use Vagrant and Virtualbox

Slide 7

Slide 7 text

Usage • Using from the command line
 hhvm foobar.php • Or you can make use of this:
 sudo /usr/bin/update-alternatives --install \
 /usr/bin/php php /usr/bin/hhvm 60 • Now you can run
 php foobar.php

Slide 8

Slide 8 text

Usage • Apache 2.2: install libapache2-mod-fastcgi ! Alias /hhvm.fastcgi /var/www/fastcgi/hhvm.fastcgi! FastCGIExternalServer /var/www/fastcgi/hhvm.fastcgi -socket /var/run/hhvm/socket -pass-header !! ! Authorization -idle-timeout 300! ! ! Order deny,allow! ! ! ! AddHandler hhvm-hack-extension .hh! AddHandler hhvm-php-extension .php! ! Action hhvm-hack-extension /hhvm.fastcgi virtual! Action hhvm-php-extension /hhvm.fastcgi virtual!

Slide 9

Slide 9 text

Usage • Apache 2.4: mod_proxy + mod_proxy_fcgi
 ProxyPass / fcgi://127.0.0.1:9000/root/path • Or
 ProxyPassMatch ^/(.*\.(hh|php)(/.*)?)$ fcgi://127.0.0.1:9000/root/path/$1

Slide 10

Slide 10 text

Usage • nginx: just like your regular php-fpm
 location ~ \.(hh|php)$ {! root /path/to/your/root! fastcgi_pass 127.0.0.1:9000;! fastcgi_index index.php;! fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;! include /etc/nginx/fastcgi_params;! }


Slide 11

Slide 11 text

Using with Composer • Add to .bashrc or equivalent:
 alias composer="hhvm -v ResourceLimit.SocketDefaultTimeout=30 -v Http.SlowQueryThreshold=30000 /usr/local/bin/composer" • Up to 5x faster

Slide 12

Slide 12 text

Extensions • HHVM ships with several common extensions, listed here:
 https://github.com/facebook/hhvm/wiki/Extensions • Usually, to add an extension, you write it in pure PHP (e.g. the Redis extension) and place it alongside the source code, to be compiled together with HHVM • You may also use HNI (HHVM-Native Interface) for hybrid PHP/C++ implementations • Can be fashioned as an externally buildable DSO, e.g. mongofill

Slide 13

Slide 13 text

Performance • Up to 2x faster compared to PHP 5.5
 (Sample benchmark performed by Christian Stocker with Symfony 2.4)
 http://blog.liip.ch/archive/2013/10/29/hhvm-and-symfony2.html

Slide 14

Slide 14 text

Caveats • PHP 5.5 generator syntax incompatibility (#1627, #1787, #1871) • Missing PHP 5.4 Closure::bind and Closure::bindTo (#1203) • Cannot set multiple cookies with same name but different path (#2494, #2526) • func_get_args() returns arguments by references instead of values (#1027) (wontfix) • array_key_exists(), reset(), end(), etc. don't work with ArrayAccess (#1221) (wontfix) • missing fastcgi_finish_request() equivalent (#1230) • https://github.com/facebook/hhvm/issues?labels=php5+incompatibility&state=open

Slide 15

Slide 15 text

Hack • Basically a superset of PHP, the most important addition being static typing • Hack files should begin with

Slide 16

Slide 16 text

Type annotations • This allows validation by the Hack typechecker before runtime • Paired with IDE support, can be helpful when refactoring code • Scalar type hinting is now possible
 class MyClass {! const int MyConst = 0;! private string $x = '';! ! public function increment(int $x): int {! $y = $x + 1;! return $y;! }! }

Slide 17

Slide 17 text

Supported types • Primitives: int, float, string, bool, array • User-defined classes: Foo, Vector • Mixed: mixed • Void: void • Nullable: ? (e.g., ?int, ?bool) • Soft: @ (e.g. @int, @bool) • Typed arrays: array, array> • Tuples: (, , ....) e.g. (string, int)

Slide 18

Slide 18 text

Supported types • XHP elements :x:frag, :x:base, :div, :xhp • Generics: Foo • Closures: (function(, , ...): return_type)
 e.g. (function(string, int): string) • Resources: resource • Continuation (generator): Continuation • Awaitable (async): Awaitable • Same type: this

Slide 19

Slide 19 text

Supported types • Note that: • Untyped arrays are not allowed in strict mode • Do not annotate return values for __construct() (typechecker will complain) • "this" only checks for same type, not same instance

Slide 20

Slide 20 text

Generics class Box {! protected T $data;! ! public function __construct(T $data) {! $this->data = $data;! }! public function setData(T $data): void {! $this->data = $data;! }! public function getData(): T {! return $this->data;! }! }! ! function swap(Box $a, Box $b): T {! $temp = $a->getData();! $a->setData($b->getData());! $b->setData($temp);! return $temp;! }! • For each instance, once a type is associated with T, it’s fixed

Slide 21

Slide 21 text

Nullable types class NullableBox {! protected ?T $data;! ! public function __construct(?T $data) {! $this->data = $data;! }! ! public function getData(): ?T {! return $this->data;! }! }! ! $box = new NullableBox(null);! ! ! function check_not_null(?int $x): int {! return $x === null ? -1 : $x;! }!

Slide 22

Slide 22 text

Soft types • Apparently not documented • Emits warnings rather than fatal errors for invalid types ! ! class Calculator {! public function add(@int $a, @int $b): @string {}! }! ! $calc = new Calculator();! $calc->add("1", "2");

Slide 23

Slide 23 text

Typed arrays • Untyped arrays are only allowed in partial or decl mode • In strict mode you must explicitly type the values: array! • Or both keys and values: array! • You can simulate PHP behaviour, but this defeats the purpose: array

Slide 24

Slide 24 text

Type aliasing • Redefine an existing type name type MyInteger = int;! • “Opaque” types disallow other files from accessing the underlying implementation (e.g. concatenation for strings) // File1.php! newtype MyString = string;! ! // File2.php! require_once "File1.php";! ! function modifyString(MyString $s): MyString {! return $s . "1"; // Hack type checker will throw an error! }

Slide 25

Slide 25 text

Tuples and shapes • Tuples are basically immutable typed arrays public function baz(): (string, int) {! return tuple("Hello", 3);! }! • Shapes are kinda like structs type MyShape = shape('id1' => string, 'id2' => int);! function foo(MyShape $x): void {}

Slide 26

Slide 26 text

Collections • Vector, Map, Set, Pair • Immutable versions: ImmVector, ImmMap, ImmSet • Can be initialised using literal syntax $vec = Vector {'foo', 'foo', 'bar'}; // integer keys! $map = Map {42 => 'foo', 73 => 'bar', 144 => 'baz'}; // ordered dictionary! $set = Set {'php', 'hack', 'hhvm'}; // unordered unique values! $par = Pair {'guid', 'ABC123'}; // only two pieces of data! • Type annotation function getTags(): Set {! return Set { "php", "hack", "hhvm" };! }

Slide 27

Slide 27 text

Collections • Some method signatures for Vector… public function __construct(?Traversable $it)! public function add(Tv $value): Vector! public function addAll(?Traversable $it): Vector! public function at(int $k): Tv! public function clear(void): Vector! public function containsKey(int $k): bool! public function count(void): int! public function filter((function(Tv): bool) $callback): Vector! public function filterWithKey((function(int, Tv): bool) $callback): Vector! public function fromArray(array $arr): Vector! public function fromItems(?Traversable $items): Vector! public function get(int $k): ?Tv! public function getIterator(void): KeyedIterator! public function isEmpty(void): bool! public function items(void): Iterable! public function keys(void): Vector! public function reverse(void): void! public function set(int $k, Tv $v): Vector! public function setAll(?KeyedTraversable $it): Vector! public function __toString(void): string! public function toValuesArray(void): array! public function zip(Traversable $iterable): Vector>

Slide 28

Slide 28 text

In other words, Hack really, really wants you to stop using simple arrays (or even ArrayObjects) as a “catch-all” data container

Slide 29

Slide 29 text

Lambdas • Use the lambda arrow ==>
 (Because -> and => are already taken): function concat(): (function(string, string): string) {! return ($x, $y) ==> {! return $y . $x;! };! }! • Implicitly capture variables from outer scope
 Can be an expression: function foo(): (function(string): string) {! $x = 'bar';! return $y ==> $y . $x;! }

Slide 30

Slide 30 text

Lambdas • Type hints are not checked at the moment • Doesn't support capturing variables by reference or returning by reference yet • Lambda arrow operator is right associative and can be chained: ! $f = $x ==> $y ==> $x + $y;! $g = $f(7);! echo $g(4); // 11

Slide 31

Slide 31 text

Variadic functions function sum(...): int {! $s = 0;! foreach (func_get_args() as $e) {! $s += $e;! }! return $s;! }! • Cannot be type annotated, unfortunately

Slide 32

Slide 32 text

Override attribute • Signify that the parent method must exist class Hello {! public function render(): void {! echo 'hello';! }! }! ! class HelloWorld extends Hello! {! <> public function render(): void {! parent::render();! echo ' world';! }! }

Slide 33

Slide 33 text

Constructor arg promotion class Person {! private string $name;! private int $age;! ! public function __construct(string $name, int $age) {! $this->name = $name;! $this->age = $age;! }! }! • can be written as ! class Person {! public function __construct(private string $name, private int $age) {}! }

Slide 34

Slide 34 text

Callbacks • This will not work in strict mode: $func = 'myFunc';! $x = $func(4);! • fun() will return a callable, which allows the typechecker to properly validate: $func = fun('myFunc');! $x = $func(4);! • Similar dubiously-named functions exist for calling static/instance methods: // $bar = array_map(array('Foo', ‘doStuff'), [1, 2, 3]);! $bar = array_map(class_meth('Foo', 'doStuff'), [1, 2, 3]);! ! $foo = new Foo();! $bar = array_map(instance_meth($foo, 'doStuff'), [1, 2, 3]);! ! $func = meth_caller('Foo', 'doStuff');! $foo = new Foo();! $x = $func($foo);

Slide 35

Slide 35 text

Async and await async function gen_foo(int $a): Awaitable {! if ($a === 0) {! return null;! }! $bar = await gen_bar($a);! if ($bar !== null) {! return $bar->getFoo();! }! return null;! }! ! async function gen_bar(int $a): Awaitable {! if ($a === 0) {! return null;! }! return new Bar();! }! ! gen_foo(4);

Slide 36

Slide 36 text

Running the type checker • Run hh_client (it will launch hh_server for you) or hh_server --check . • Recursively looks for directories that contain a .hhconfig file (it won’t run if this is missing) • Optionally return output in json format • Note: does not follow symlinks

Slide 37

Slide 37 text

Unsupported features • Still runs in HHVM, but the type checker does not like the following: • goto, if: … endif; etc • AND, OR, XOR • References (&) • Error suppression (@) • break N, continue N • eval() • globals

Slide 38

Slide 38 text

Unsupported features • list(, $b) = array(3, 4); should be list($_, $b) = array(3, 4); • Function calls are case-sensitive • Strict mode does not support top-level code except for require() and require_once(); i.e. everything else must be in a class or function • Does not support "variable variables" (e.g. $$a) or extract() • Cannot call parent::staticMethod() • Cannot declare a class method with a name that collides with class name • Cannot pass primitives by reference

Slide 39

Slide 39 text

Drawbacks • Still new, not yet 100% compatibility (but catching up fast) • Your favourite extension may not be available • Limited IDE support at the moment (weekend project idea?) • Hack-exclusive libraries? Package repos? Community fragmentation? • Clashes with PHP 5.5 and future 5.6 syntax
 (generators and variadic functions)

Slide 40

Slide 40 text

• Generator functions are of the type “Continuation” in HHVM (since they were implemented earlier) • The following is valid in PHP 5.5 but not in HHVM: $data = (yield $value); // delete the brackets for HHVM! $data = yield; // HHVM needs expression after yield! • HHVM Continuations need to be “primed” unlike PHP 5.5 Generators $generator = construct_generator();! $generator->current(); // must call next() first in HHVM!

Slide 41

Slide 41 text

• Proposed PHP 5.6 syntax for variadic functions: function fn($arg, ...$args) {}! function fn($arg, &...$args) {}! function fn($arg, callable ...$args) {}! • Type-hinting and arguments by value not supported in HHVM / Hack function fn(...): void {}

Slide 42

Slide 42 text

Benefits • Type safety!!! (Always use the type checker) • Syntactic sugar from other languages • Discard “bad” parts of PHP • Active community (e.g. New Relic has released a prototype HHVM extension, Heroku just announced HHVM support)

Slide 43

Slide 43 text

Resources • http://hhvm.com/ • http://hacklang.org/ • http://docs.hhvm.com/manual/en/hacklangref.php • https://blog.engineyard.com/2014/hhvm-hack • http://blog.vjeux.com/2014/javascript/hack-is-to-php-what-es6-is-to- javascript.html • https://github.com/facebook/hhvm

Slide 44

Slide 44 text

Thank you Contact: • Chris Heng • https://github.com/gigablah