Upgrade to Pro — share decks privately, control downloads, hide ads and more …

HipHop Virtual Machine (HHVM) for PHP and The hack language

HipHop Virtual Machine (HHVM) for PHP and The hack language

A talk about HHVM and Hack at the Webtuesday Zurich on 8 April 2014.

Christian Stocker

April 08, 2014
Tweet

Other Decks in Programming

Transcript

  1. Agile Web Development
    Liip.ch
    !

    Zürich, 2014
    HIPHOP VIRTUAL MACHINE (HHVM)
    FOR PHP AND THE HACK LANGUAGE
    Webtuesday, 8. April 2014

    View Slide

  2. AGENDA
    - HHVM - The Engine
    - Hack - The Language
    !
    - If you have questions during the talk, just ask (or at the end)

    View Slide

  3. ABOUT ME AND WHY I TALK ABOUT HHVM
    - Partner at Liip
    - @chregu on Twi!er (and almost everywhere else)
    - PHP “Core” developer (when I was young ;) )
    !
    - I work together with a Liip team on a big project for the Migros
    - We use HHVM on that project in production

    View Slide

  4. HHVM - WHAT IS IT
    - HHVM = HipHop Virtual Machine
    - A PHP Virtual Machine wri!en by Facebook
    - Goal: Make it much faster than “Zend” PHP
    - And be compatible to PHP (one way at least)
    - Language additions to PHP, called Hack
    - Open sourced in late 2011 (PHP License)
    - Mainly wri!en in C++, PHP and OCaml

    View Slide

  5. HHVM - THE (SHORT) HISTORY
    - In 2008, Facebook startet with HPHP
    - A PHP to C++ compiler => HPHPc
    - Compiling to a (huge) binary
    - Up to 6x faster than Zend PHP
    - Also: HPHi (for local dev) and HPHPd (for debugging)
    - Deprecated in 2013
    !
    - HHVM began in 2010
    - Bytecode compiler, then JIT to native code
    - Full support of PHP 5.4

    View Slide

  6. HHVM - TODAY
    - Drop in replacement for PHP-FPM via fast-cgi
    - Version at 3.0.1
    - Supports many PHP frameworks out of the box (see h!p://
    hhvm.com/frameworks)
    - Supports many extension (new ones since 3.0 for example
    XSLT, imagick and mysqli)
    - Hack is documented
    - Quite easily installable on Debian based systems
    - Runs anywhere which is 64-bit x86 linux (on os x kind of,
    Windows and ARM support is coming)

    View Slide

  7. HHVM - INSTALLATION - DEBIAN
    deb http://dl.hhvm.com/ubuntu saucy main
    apt-get update
    apt-get install hhvm
    /etc/init.d/hhvm start
    !
    and in nginx config
    !
    location ~ \.php$ {!
    fastcgi_pass 127.0.0.1:9000;!
    fastcgi_index index.php;!
    fastcgi_param SCRIPT_FILENAME!
    /var/www$fastcgi_script_name;!
    include fastcgi_param;!
    }

    View Slide

  8. HHVM - INSTALLATION - SUSE
    # this is needed for everything
    !
    export ABI=64
    export LD_LIBRARY_PATH=/srv/www/vhosts/api/hhvm/lib64:/srv/www/vhosts/api/hhvm/lib:$LD_LIBRARY_PATH
    export PATH=/srv/www/vhosts/api/hhvm/bin/:$PATH
    export SRCFOLDER=/srv/www/vhosts/api/hhvm/src
    !
    mkdir -p $SRCFOLDER
    cd $SRCFOLDER
    !
    # INSTALL all the dependencies, you only have to do this once
    !
    #CMAKE
    !
    cd $SRCFOLDER
    wget http://www.cmake.org/files/v2.8/cmake-2.8.12.1.tar.gz
    tar -xzf cmake-2.8.12.1.tar.gz
    cd cmake
    ./configure --prefix=/srv/www/vhosts/api/hhvm/
    make install
    !
    #gmp
    !
    cd $SRCFOLDER
    wget https://gmplib.org/download/gmp/gmp-5.1.3.tar.bz2
    tar -xjf gmp-5.1.3.tar.bz2
    cd gmp-5.1.3
    ./configure --prefix=/srv/www/vhosts/api/hhvm/
    make install
    !
    #mpfr
    !
    cd $SRCFOLDER
    wget http://www.mpfr.org/mpfr-current/mpfr-3.1.2.tar.bz2
    cd mpfr-3.1.2
    ./configure --prefix=/srv/www/vhosts/api/hhvm/ --with-gmp=/srv/www/vhosts/api/hhvm/
    make install
    !
    #mpc
    !
    cd $SRCFOLDER
    wget http://www.multiprecision.org/mpc/download/mpc-1.0.1.tar.gz
    cd mpc-1.0.1
    ./configure --prefix=/srv/www/vhosts/api/hhvm/ --with-gmp=/srv/www/vhosts/api/hhvm/
    make install
    !
    !
    !
    !

    View Slide

  9. HHVM - INSTALLATION - SUSE
    #isl
    !
    cd $SRCFOLDER
    wget http://isl.gforge.inria.fr/isl-0.12.tar.bz2
    tar -xjf isl-0.12.tar.bz2
    cd isl-0.12
    ./configure --prefix=/srv/www/vhosts/api/hhvm/ --with-gmp-prefix=/srv/www/vhosts/api/hhvm/
    make install
    !
    #GCC
    !
    cd $SRCFOLDER
    wget ftp://ftp.gwdg.de/pub/misc/gcc/releases/gcc-4.8.2/gcc-4.8.2.tar.bz2
    tar -xjf gcc-4.8.2.tar.bz2
    cd gcc-4.8.2
    ./configure --prefix=/srv/www/vhosts/api/hhvm/ --with-isl=/srv/www/vhosts/api/hhvm --with-gmp=/srv/www/vhosts/api/hhvm/ --with-mpc=/srv/www/vhosts/api/hhvm/
    mpfr=/srv/www/vhosts/api/hhvm/
    make install
    !
    #bzip
    !
    cd $SRCFOLDER
    cd bzip2-1.0.6
    ./configure --prefix=/srv/www/vhosts/api/hhvm/
    make -f Makefile-libbz2_so
    make install PREFIX=/srv/www/vhosts/api/hhvm/
    cd ..
    #python (needed for boost)
    !
    cd $SRCFOLDER
    wget http://www.python.org/ftp/python/2.6.9/Python-2.6.9.tgz
    tar -xzf Python-2.6.9.tgz
    cd Python-2.6.9
    ./configure --prefix=/srv/www/vhosts/api/hhvm/ --enable-shared
    make install
    !
    #boost
    !
    cd $SRCFOLDER
    wget http://sourceforge.net/projects/boost/files/boost/1.55.0/boost_1_55_0.tar.bz2/download
    tar -xjf boost_1_55_0.tar.bz2
    cd boost_1_55_0
    ls
    ./bootstrap.sh --with-python=/srv/www/vhosts/api/hhvm/bin/python --prefix=/srv/www/vhosts/api/hhvm
    ./b2
    ./bjam --layout=system install
    !
    !
    !

    View Slide

  10. HHVM - INSTALLATION - SUSE
    #libevent
    !
    cd $SRCFOLDER
    wget https://github.com/downloads/libevent/libevent/libevent-1.4.14b-stable.tar.gz
    tar -xzf libevent-1.4.14b-stable.tar.gz
    cd libevent-1.4.14b-stable
    cat ../hhvm/hphp/third_party/libevent-1.4.14.fb-changes.diff | patch -p1
    ./autogen.sh
    autoreconf --force --install
    ./configure --prefix=/srv/www/vhosts/api/hhvm/
    make
    make install
    !
    #libcurl
    !
    cd $SRCFOLDER
    mkdir /srv/www/vhosts/api/hhvm/etc/curlssl
    wget -O /srv/www/vhosts/api/hhvm/etc/curlssl/cacert.pem http://curl.haxx.se/ca/cacert.pem
    wget http://curl.haxx.se/download/curl-7.36.0.tar.gz
    tar -xzf curl-7.36.0.tar.gz
    cd curl-7.36.0
    ./configure --prefix=/srv/www/vhosts/api/hhvm/ --with-ca-bundle=/srv/www/vhosts/api/hhvm/etc/curlssl/cacert.pem
    make
    make install
    !
    #google glog
    !
    cd $SRCFOLDER
    wget https://google-glog.googlecode.com/files/glog-0.3.3.tar.gz
    tar -xzf glog-0.3.3.tar.gz
    cd glog-0.3.3
    ./configure --prefix=/srv/www/vhosts/api/hhvm/
    make
    make install
    !
    #memcached
    !
    cd $SRCFOLDER
    wget http://www.memcached.org/files/memcached-1.4.16.tar.gz
    tar -xzf memcached-1.4.16.tar.gz
    ./configure --prefix=/srv/www/vhosts/api/hhvm/
    make
    make install
    !
    !
    !
    !
    !
    !

    View Slide

  11. HHVM - INSTALLATION - SUSE
    #libmemcached (1.0.17 doesn't work)
    !
    cd $SRCFOLDER
    wget https://launchpad.net/libmemcached/1.0/1.0.16/+download/libmemcached-1.0.16.tar.gz
    tar -xzf libmemcached-1.0.16.tar.gz
    cd libmemcached-1.0.16
    ./configure --prefix=/srv/www/vhosts/api/hhvm/ --with-memcached=/srv/www/vhosts/api/hhvm/bin/memcached
    make
    make install
    !
    #jemalloc
    !
    cd $SRCFOLDER
    wget http://www.canonware.com/download/jemalloc/jemalloc-3.4.1.tar.bz2
    tar -xjf jemalloc-3.4.1.tar.bz2
    cd jemalloc-3.4.1
    ./configure --prefix=/srv/www/vhosts/api/hhvm/
    make
    make install
    !
    #tbb
    !
    cd $SRCFOLDER
    wget --no-check-certificate https://www.threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb42_20131118oss_src.tgz
    tar -xzf tbb42_20131118oss_src.tgz
    cd tbb42_20131118oss
    make
    mkdir -p /srv/www/vhosts/api/hhvm/include/serial
    cp -a include/serial/* /srv/www/vhosts/api/hhvm/include/serial/
    mkdir -p /srv/www/vhosts/api/hhvm/include/tbb
    cp -a include/tbb/* /srv/www/vhosts/api/hhvm/include/tbb/
    cp build/linux_intel64_gcc_cc4.8.2_libc_kernel3.0.82_release/libtbb.so.2 /srv/www/vhosts/api/hhvm/lib64/
    ln -s /srv/www/vhosts/api/hhvm/lib64/libtbb.so.2 /srv/www/vhosts/api/hhvm/lib64/libtbb.so
    !
    # mysql
    !
    cd $SRCFOLDER
    wget http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.15.tar.gz
    tar -xzf mysql-5.6.15.tar.gz
    cd mysql-5.6.15
    cmake . -DWITHOUT_SERVER=ON -DCMAKE_INSTALL_PREFIX=/srv/www/vhosts/api/hhvm
    make
    make install
    cd ..
    !
    !
    !
    !
    !

    View Slide

  12. HHVM - INSTALLATION - SUSE
    #gd
    !
    cd $SRCFOLDER
    wget https://bitbucket.org/libgd/gd-libgd/downloads/libgd-2.1.0.tar.bz2
    tar -xjf libgd-2.1.0.tar.bz2
    cd libgd-2.1.0
    ./configure --prefix=/srv/www/vhosts/api/hhvm/
    make install
    !
    #expat
    !
    cd $SRCFOLDER
    wget http://downloads.sourceforge.net/project/expat/expat/2.1.0/expat-2.1.0.tar.gz
    tar -xzf expat-2.1.0.tar.gz
    cd expat-2.1.0
    ./configure --prefix=/srv/www/vhosts/api/hhvm/
    make install
    !
    #icu
    !
    cd $SRCFOLDER
    wget http://download.icu-project.org/files/icu4c/52.1/icu4c-52_1-src.tgz
    tar -xzf icu4c-52_1-src.tgz
    cd icu/source
    ./configure --prefix=/srv/www/vhosts/api/hhvm/make install
    !
    #libmcrypt
    !
    cd $SRCFOLDER
    wget http://downloads.sourceforge.net/project/mcrypt/Libmcrypt/2.5.8/libmcrypt-2.5.8.tar.bz2
    tar -xjf libmcrypt-2.5.8.tar.bz2
    cd libmcrypt-2.5.8
    ./configure --prefix=/srv/www/vhosts/api/hhvm/
    make
    make install
    !
    #openssl
    !
    cd $SRCFOLDER
    wget https://www.openssl.org/source/openssl-1.0.1g.tar.gz
    tar xzf openssl-1.0.1g.tar.gz
    cd openssl-1.0.1g
    ./config --prefix=/srv/www/vhosts/api/hhvm/
    make
    make install
    !
    !
    !
    !

    View Slide

  13. HHVM - INSTALLATION - SUSE
    #oniguruma
    !
    cd $SRCFOLDER
    http://www.geocities.jp/kosako3/oniguruma/archive/onig-5.9.5.tar.gz
    tar -xzf onig-5.9.5.tar.gz
    cd onig-5.9.5
    ./configure --prefix=/srv/www/vhosts/api/hhvm/
    make
    make install
    !
    #ldap
    !
    cd $SRCFOLDER
    wget ftp://sunsite.cnlab-switch.ch/mirror/OpenLDAP/openldap-release/openldap-2.4.38.tgz
    tar -xzf openldap-2.4.38.tgz
    cd openldap-2.4.38
    ./configure --prefix=/srv/www/vhosts/api/hhvm/ --disable-slapd --disable-bdb
    make
    make install
    !
    #libedit
    !
    cd $SRCFOLDER
    wget http://thrysoee.dk/editline/libedit-20130712-3.1.tar.gz
    tar -xzf libedit-20130712-3.1.tar.gz
    cd libedit-20130712-3.1
    ./configure --prefix=/srv/www/vhosts/api/hhvm/
    make install
    !
    #libelf
    !
    cd $SRCFOLDER
    wget http://www.mr511.de/software/libelf-0.8.9.tar.gz
    tar -xzf libelf-0.8.9.tar.gz
    cd libelf-0.8.9
    ./configure --prefix=/srv/www/vhosts/api/hhvm/
    make
    make install
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !

    View Slide

  14. HHVM - INSTALLATION - SUSE
    #dwarf
    !
    cd $SRCFOLDER
    wget http://gentoo.skyfms.com/distfiles/libdwarf-20120410.tar.gz
    cd dwarf-20120410/libdwarf
    ./configure --prefix=/srv/www/vhosts/api/hhvm/ --enable-shared
    make
    cp libdwarf/libdwarf.a /srv/www/vhosts/api/hhvm/lib64/
    cp libdwarf/libdwarf.h /srv/www/vhosts/api/hhvm/include/
    cp libdwarf/dwarf.h /srv/www/vhosts/api/hhvm/include/
    !
    #cclient
    !
    cd $SRCFOLDER
    wget ftp://ftp.cac.washington.edu/imap/imap-2007f.tar.gz
    cd imap-2007f
    make slx SSLTYPE=none
    cp -r c-client ../../include/
    cp -r c-client/c-client.a ../../lib/libc-client4.a
    !
    #attr
    !
    cd $SRCFOLDER
    wget http://download.savannah.gnu.org/releases-noredirect/attr/attr-2.4.46.src.tar.gz
    tar -xzf attr-2.4.46.src.tar.gz
    cd attr-2.4.46
    ./configure --prefix=/srv/www/vhosts/api/hhvm/
    make install
    cp libattr/.libs/libattr.so ../../lib/
    !
    #libcap
    cd $SRCFOLDER
    wget ftp://ftp.de.debian.org/debian/pool/main/libc/libcap2/libcap2_2.22.orig.tar.gz
    tar -xzf libcap2_2.22.orig.tar.gz
    cd libcap-2.22/
    export prefix=/srv/www/vhosts/api/hhvm/lib
    export LDFLAGS="-L /srv/www/vhosts/api/hhvm/lib"
    make
    make install
    !
    #binutils
    !
    cd $SRCFOLDER
    wget http://ftp.gnu.org/gnu/binutils/binutils-2.24.tar.bz2
    tar -xjf binutils-2.24.tar.bz2
    cd binutils-2.24
    ./configure —prefix=/srv/www/vhosts/api/hhvm
    !
    !

    View Slide

  15. HHVM - INSTALLATION - SUSE
    #libxslt
    !
    cd $SRCFOLDER
    wget ftp://xmlsoft.org/libxslt/libxslt-1.1.28.tar.gz
    tar -xzf libxslt-1.1.28.tar.gz
    cd libxslt-1.1.28
    ./configure --prefix=/srv/www/vhosts/api/hhvm
    make
    make install
    !
    # imagick
    !
    cd $SRCFOLDER
    wget http://mirror.checkdomain.de/imagemagick/ImageMagick-6.8.8-9.tar.gz
    tar -xf ImageMagick-6.8.8-9.tar.gz
    cd ImageMagick-6.8.8-9
    make
    make install
    !

    View Slide

  16. HHVM - INSTALLATION - SUSE
    # since hhvm 3.0 we switched to fastcgi via nginx
    # nginx
    !
    cd $SRCFOLDER
    wget http://nginx.org/download/nginx-1.4.7.tar.gz
    tar -xzf nginx-1.4.7.tar.gz
    cd nginx-1.4.7
    ./configure --prefix=/srv/www/vhosts/api/hhvm --http-log-path=/srv/www/vhosts/api/shared/app/logs/nginx-access.log --error-log-path=/srv/www/vhosts/api/shar
    nginx-error.log --conf-path=/srv/www/vhosts/api/hhvm/etc/nginx/nginx.conf --pid-path=/srv/www/vhosts/api/pids/nginx.pid --http-fastcgi-temp-path=/srv/www/vh
    mkdir /srv/www/vhosts/api/hhvm/etc/nginx/
    make
    make install
    !
    # INSTALL all the depend
    !
    #hhvm
    !
    cd $SRCFOLDER
    git clone https://github.com/facebook/hhvm.git
    cd hhvm
    git submodule init
    git submodule update
    export HPHP_HOME=`/bin/pwd`
    ./configure -DCMAKE_PREFIX_PATH=/srv/www/vhosts/api/hhvm/ \
    -DCMAKE_C_COMPILER=/srv/www/vhosts/api/hhvm/bin/gcc \
    -DCMAKE_INCLUDE_PATH=/srv/www/vhosts/api/hhvm/include \
    -DCMAKE_INSTALL_PREFIX=/srv/www/vhosts/api/hhvm/ \
    -DLIBMAGICKWAND_INCLUDE_DIRS=/srv/www/vhosts/api/hhvm/include/ImageMagick-6 \
    -DLIBMAGICKWAND_LIBRARIES=/srv/www/vhosts/api/hhvm/lib/libMagickWand-6.Q16.so
    # evt. noch
    # cmake -D HOTPROFILER:BOOL=ON .
    make install

    View Slide

  17. HHVM - INSTALLATION - SUSE
    PHEEEEW …
    (Maybe not everything was actually needed to built from source
    and SuSE would have provided it, but we were not the
    sysadmins ;))

    View Slide

  18. HHVM - PERFORMANCE
    - Is it actually much faster?
    - YES!
    - But of course it depends
    !
    - Without JIT, it isn’t (in CLI for example)
    - JIT needs some warm up requests to find the hot paths
    - The more your scripts do, the more you gain.

    View Slide

  19. HHVM - PERFORMANCE TESTS
    - Done with siege on the servers of the Migros project
    - 16 CPU, 96 GB RAM, non virtualized
    - Symfony 2.4 as PHP Framework
    - Returns a JSON with product information
    - Retrieved from ElasticSearch (no SQL DB involved here)
    - Transformed with JMSSerializer
    !
    - Tested with different concurrencies (2 - 80)
    - Tested against
    - PHP 5.3/apc with Apache Prefork
    - PHP 5.5/opcache with nginx
    - HHVM 3.0 with nginx

    View Slide

  20. HHVM - SOME CHARTS
    Get 1 Product from the API (a small request)
    requests per second
    0
    20
    40
    60
    80
    2 4 6 10 20 40 80
    PHP 5.3/apache PHP 5.5/fpm HHVM 3.0
    ms per request
    0
    450
    900
    1350
    1800
    2 4 6 10 20 40 80
    PHP 5.3/apache PHP 5.5/fpm HHVM 3.0

    View Slide

  21. HHVM - SOME CHARTS
    Get 16 products from the API (a medium request)
    requests per second
    0
    13
    26
    39
    52
    2 4 6 10 20 40 80
    PHP 5.3/apache PHP 5.5/fpm HHVM 3.0
    ms per request
    0
    1000
    2000
    3000
    4000
    2 4 6 10 20 40 80
    PHP 5.3/apache PHP 5.5/fpm HHVM 3.0

    View Slide

  22. HHVM - SOME CHARTS
    Get 50 products from the API (a large request)
    requests per second
    0
    7
    14
    21
    28
    2 4 6 10 20 40 80
    PHP 5.3/apache PHP 5.5/fpm HHVM 3.0
    ms per request
    0
    2250
    4500
    6750
    9000
    2 4 6 10 20 40 80
    PHP 5.3/apache PHP 5.5/fpm HHVM 3.0

    View Slide

  23. HHVM - PERFORMANCE SUMMARY
    - HHVM is up to 3.5 times faster than PHP 5.3
    - HHVM is up to 2 times faster than PHP 5.5
    - PHP 5.5 is up to 1.7 times faster than PHP 5.3
    - HHVM scales a li!le bit be!er with concurrency
    - (load of server was also lower)
    - The longer your requests, the more you save
    !
    !
    - Others came to similar conclusions ;)

    View Slide

  24. HHVM - PROFILING
    - xhprof is included
    - But you need to recompile HHVM with
    - cmake -D HOTPROFILER:BOOL=ON .
    - (it doesn’t have much performance impact)
    !
    - You can use the usual xhprof tools
    !
    - We also use New Relic with HHVM. See end of talk

    View Slide

  25. HHVM - DEBUGGING
    - With HPHPd - HPHP Debugger
    - Interactive shell
    -  GDB-like debugging
    -  Standalone or w/ server
    -  Breakpoints
    -  Watches
    -  Macros

    View Slide

  26. THE HACK LANGUAGE
    PHP on Steroids

    View Slide

  27. HACK - TYPE HINTING
    - Scalars
    - bool, int, float, num, string
    - Return typehints
    - Typed properties
    - Constructor arg promotion
    !
    - Static analyzer (hh_client/hh_server) looks for mismatches and
    errors without running code

    View Slide

  28. HACK - TYPE HINTING
    !
    class Foo {
    !
    //Typed properties (and scalar typehint)
    private int $num = 123;
    !
    //Return typehints
    public function add(int $delta): Foo {
    $this->num += $delta;
    return $this;
    }
    !
    public function get(): int {
    return $this->num;
    }
    !
    // Constructor arg promotion
    public function __constructor(private int $num): void {
    }
    }
    !
    //needed, typechecker doesn't check in global space
    function main() {
    !
    $f = new Foo(123);
    $f->add(456);
    !
    // gives error with hh_client
    $f->add("banana");
    }
    !
    main();

    View Slide

  29. HACK - TYPE CHECKER
    - hh_client / hh_server
    - Only runs on linux right now, needs OCaml
    - hh_client spawns hh_server
    - hh_server watches file system on each save
    - makes hh_client really fast
    - doesn’t check with !
    - Integration for vim and emacs available, more should come

    View Slide

  30. HACK - GENERICS
    - You may know them from other languages like C# or Java
    - Allow classes and methods to be parameterized
    !
    class Value {
    public function __construct(protected T $value) {
    }
    !
    public function getValue(): T {
    return $this->value;
    }
    !
    public function addString(string $bar) {
    }
    }
    !
    function main2() {
    $st = new Value("TestString");
    $st->addString($st->getValue());
    !
    $st = new Value(42);
    //errors out, since getValue returns int
    //$st->addString($st->getValue());
    }
    !
    main2();

    View Slide

  31. HACK - COLLECTIONS
    - Specialized array objects
    - Vector (an ordered, index-based list)
    - Map (an ordered dictionary)
    - Set (a list of unique values)
    - Pair (an index-based collection of exactly two elements)
    - All also as Immutable classes
    - Clear interface
    - Literal syntax
    - It can be defined, what’s in those collections

    View Slide

  32. HACK - COLLECTIONS
    !
    function CollectionDemo( Vector $nums,
    Set $names,
    Map $numNameMap,
    ImmVector $nums2): bool {
    !
    foreach($nums as $num) {
    $mappedName = $numNameMap[$num];
    if ($names->contains($mappedName)) {
    return true;
    }
    }
    if ($nums2->count() == 0) return true;
    return false;
    }
    !
    function main3() {
    $vector = Vector {1, 2, 3};
    $set = Set {"foo", "bar", "baz"};
    $map = Map { 1 => "hello", 2 => "world" , 3 => "baz"};
    $frozen = ImmVector{5,6};
    var_dump(CollectionDemo($vector, $set, $map, $frozen));
    }
    !
    main3();
    !

    View Slide

  33. HACK - TYPE ALIASING AND SHAPES
    - Type aliasing allows to redeclare a type
    - Opaque Type aliasing restricts access to underlying
    implementation
    - Shapes are like struct in other languages, but for arrays
    - Helps in type checking
    !
    //type alias
    type Point = (int, int);
    //opaque type alias
    newtype SecretID = int;
    //shape
    type Point2D = shape('x' => int, 'y' => int);
    !
    function create_point(int $x, int $y): Point {
    return tuple($x, $y);
    }
    !
    function dotProduct(Point2D $a, Point2D $b): int {
    return $a['x'] * $b['x'] + $a['y'] * $b['y'];
    }

    View Slide

  34. HACK - OPAQUE TYPE ALIASING
    // File1.php
    !
    newtype SecretID = int;
    !
    function modify_secret_id(SecretID $sid): SecretID {
    return $sid - time() - 2042;
    }
    !
    function main_ot1(): void {
    echo modify_secret_id(44596);
    }
    !
    main_ot1();
    !
    !
    // File2.php
    !
    require_once "opaquetypealiasing.php";
    !
    function try_modify_secret_id(SecretID $sid): SecretID {
    //gives an error, because it’s an operation on int
    return $sid + time() + 2000;
    }
    !
    function main_ot2(): void {
    //gives an error, because it’s an int not a SecretID
    try_modify_secret_id(44596);
    }
    !
    main_ot2();

    View Slide

  35. HACK - LAMBDA EXPRESSION
    - Like closures, but shorter
    - Implicitly captures variables from outer scope
    !
    $foo = $x ==> $x + 1;
    $foo(12); // returns 13
    !
    $foo = () ==> 73;
    $foo(); // returns 73
    !
    $bar = ($x,$y) ==> $x + $y;
    $bar(3,8); // returns 11
    !
    //type hints (not supported yet by the typechecker, gives an error)
    $captured = "test: ";
    $bar = (string $k = "foo"): string ==> $captured . $k;
    !

    View Slide

  36. HACK - ASYNC OPERATIONS
    - Parallelizing made “easy”
    - Allow multiple functions to run “simultaneously”
    - While one is blocking, the other executes
    - NOT threading
    - A li!le bit complicated right now, but more async native
    functions (database, scheduling, memory handling) will come
    // simplefied example, does not work this way, see next slide
    !
    async function getPage($url) {
    $fp = fopen($url, 'r');
    await $fp;
    return stream_get_contents($fp);
    }
    !
    $pages = await [
    getPage('http://php.net'),
    getPage('http://example.com'),
    getPage('http://hhvm.com'),
    ];

    View Slide

  37. HACK - ASYNC OPERATIONS
    !
    class Fetcher {
    // async function: http://docs.hhvm.com/manual/en/hack.async.php
    // return type annotation: http://docs.hhvm.com/manual/en/hack.annotations.introexample.php
    public async function fetch(string $url) : Awaitable {
    $ch1 = curl_init();
    print "get $url \n";
    !
    curl_setopt($ch1, CURLOPT_URL, $url);
    curl_setopt($ch1, CURLOPT_HEADER, 0);
    curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
    !
    $mh = curl_multi_init();
    curl_multi_add_handle($mh,$ch1);
    !
    $active = null;
    do {
    $mrc = curl_multi_exec($mh, $active);
    // reschedule it for async to work properly
    await RescheduleWaitHandle::Create(1, 1);
    } while ($mrc == CURLM_CALL_MULTI_PERFORM);
    !
    while ($active && $mrc == CURLM_OK) {
    if (curl_multi_select($mh) != -1) {
    do {
    $mrc = curl_multi_exec($mh, $active);
    await RescheduleWaitHandle::Create(1, 1); // simulate blocking I/O
    } while ($mrc == CURLM_CALL_MULTI_PERFORM);
    }
    }
    print "finished $url\n";
    return 1;
    }
    }
    !

    View Slide

  38. !
    class Fetch {
    !
    protected Fetcher $fetcher;
    !
    //Constructor Argument Promotion http://docs.hhvm.com/manual/en/hack.constructorargumentpromotion.php
    //Vector http://docs.hhvm.com/manual/en/hack.collections.vector.php (instead of array)
    //Annotating Arrays and Collections: http://docs.hhvm.com/manual/en/hack.annotations.arrays.php
    public function __construct(private Vector $urls) {
    $this->fetcher = new Fetcher();
    }
    !
    public async function run() : Awaitable {
    !
    //lambda expressions: http://docs.hhvm.com/manual/en/hack.lambda.php
    $waithandles = $this->urls->map($url ==> $this->fetcher->fetch($url));
    !
    // works too, but not supported by typechecker yet
    //$waithandles = $this->urls->map((string $url): Awaitable ==> $this->fetcher->fetch($url));
    // same as above, but with closure and annotations, so it catches type errors
    //$waithandles = $this->urls->map(function(string $url): Awaitable {return $this->fetcher->fetch($url);});
    !
    //create wait handle for all and only continue when all have finished
    $x = await GenVectorWaitHandle::Create($waithandles);
    return $x->count();
    }
    !
    public function start() : string {
    return $this->run()->join() . " urls fetched and finished\n";
    }
    }
    !
    function main4() {
    //Vector with Literal Syntax: http://docs.hhvm.com/manual/en/hack.collections.literalsyntax.php
    $urls = Vector{"http://chregu.tv/webinc/sleep.php?s=1","http://chregu.tv/webinc/sleep.php?s=1"};
    $f = new Fetch($urls);
    print $f->start();
    }
    main4();
    !
    !

    View Slide

  39. HACK - FURTHER FEATURES
    - Nullable Types. ?int, ?string, ?class
    - User A!ributes (accessible via Reflection)
    - XHP – XHtml for PHP (Templating)
    - Continuations (like Generators in PHP)
    - Tuples (fixed size arrays)
    - Override A!ribute (define in a child class that there must be a
    parent class)

    View Slide

  40. HHVM - WRITING EXTENSIONS
    - It’s not that hard (compared to PHP extensions anyway)
    - You can write the “easy” stuff in PHP/Hack
    - And switch to C++ for the harder stuff
    !
    - We wrote an extension to use New Relic with HHVM
    - See blog.liip.ch/archive/2014/03/27/hhvm-and-new-relic.html
    for details

    View Slide

  41. HHVM - WRITING EXTENSIONS
    //The same as newrelic_add_attribute, but like in the officical NewRelic PHP API
    function newrelic_add_custom_parameter(string $name, string $value) {
    newrelic_add_attribute_intern($name, $value);
    }
    !
    function newrelic_notice_error(string $error_message, \Exception $e = null) {
    if ($e) {
    if (!$error_message) {
    $error_message = $e->getMessage();
    }
    $exception_type = get_class($e);
    $stack_trace = $e->getTraceAsString();
    } else {
    $exception_type = "";
    $stack_trace = NewRelicExtensionHelper::debug_backtrace_string();
    }
    $stack_frame_delimiter = "\n";
    newrelic_notice_error_intern( $exception_type, $error_message, $stack_trace, $stack_frame_delimiter);
    }
    function newrelic_start_transaction(string $appname, string $license = null) {
    newrelic_start_transaction_intern();
    newrelic_transaction_set_request_url($_SERVER["REQUEST_URI"]);
    }
    !
    //...
    !
    <<__Native>>
    function newrelic_start_transaction_intern(): int;
    !
    <<__Native>>
    function newrelic_name_transaction_intern(string $name): int;
    !
    <<__Native>>
    function newrelic_transaction_set_request_url(string $name): int;
    !
    <<__Native>>
    function newrelic_transaction_set_threshold(int $threshold): int;
    !

    View Slide

  42. // newrelic.cpp
    #include "hphp/runtime/base/base-includes.h"
    #include "hphp/runtime/ext/ext_error.h"
    #include "newrelic_transaction.h"
    #include "newrelic_collector_client.h"
    #include "newrelic_common.h"
    //...
    using namespace std;
    namespace HPHP {
    bool keep_running = true;
    static int64_t HHVM_FUNCTION(newrelic_start_transaction_intern) {
    long transaction_id = newrelic_transaction_begin();
    return transaction_id;
    }
    static int HHVM_FUNCTION(newrelic_name_transaction_intern, const String & name) {
    return newrelic_transaction_set_name(NEWRELIC_AUTOSCOPE, name.c_str());
    }
    static int HHVM_FUNCTION(newrelic_transaction_set_request_url, const String & request_url) {
    return newrelic_transaction_set_request_url(NEWRELIC_AUTOSCOPE, request_url.c_str());
    }
    //...
    static class NewRelicExtension : public Extension {
    public:
    NewRelicExtension () : Extension("newrelic") {
    config_loaded = false;
    }
    virtual void init_newrelic() {
    newrelic_register_message_handler(newrelic_message_handler);
    newrelic_init(license_key.c_str(), app_name.c_str(), app_language.c_str(), app_language_version.c_str());
    }
    virtual void moduleLoad(Hdf config) {
    if (!config.exists("EnvVariables")) return;
    Hdf env_vars = config["EnvVariables"];
    //...
    }
    virtual void moduleInit () {
    if (config_loaded) init_newrelic();
    !
    HHVM_FE(newrelic_start_transaction_intern);
    HHVM_FE(newrelic_name_transaction_intern);
    HHVM_FE(newrelic_transaction_set_request_url);
    //...
    loadSystemlib();
    }
    virtual void requestShutdown() {
    newrelic_transaction_end(NEWRELIC_AUTOSCOPE);
    }
    virtual void requestInit() {
    f_set_error_handler(s__NR_ERROR_CALLBACK);
    f_set_exception_handler(s__NR_EXCEPTION_CALLBACK);
    //TODO: make it possible to disable that via ini
    GlobalVariables *g = get_global_variables();
    newrelic_transaction_begin();
    String request_url = g->get(s__SERVER).toArray()[s__REQUEST_URI].toString();
    newrelic_transaction_set_request_url(NEWRELIC_AUTOSCOPE, request_url.c_str());
    String script_name = g->get(s__SERVER).toArray()[s__SCRIPT_NAME].toString();
    newrelic_transaction_set_name(NEWRELIC_AUTOSCOPE, script_name.c_str());
    }
    } s_newrelic_extension;
    HHVM_GET_MODULE(newrelic)
    } // namespace HPHP

    View Slide

  43. HHVM - DRAWBACKS?
    - Not every library works yet (eg. Doctrine DBAL only in dev
    branch)
    - Not really open dev model, Facebook controls it totally (and
    CLA needed for contribution), the far future is unknown
    - Still kind of moving target
    - Type Checker only really useful, when all your important
    classes are converted to - No easy way back, when you start using Hack.
    - If you need exotic extensions …

    View Slide

  44. Agile Web Development
    Liip.ch
    !

    Christian Stocker
    @chregu
    [email protected]
    QUESTIONS?
    And some links:
    !
    - The examples from this talk: 

    github.com/chregu/hack-examples
    - The HHVM site: hhvm.com - with a blog: hhvm.com/blog
    - HHVM/Hack Docs: docs.hhvm.com
    - Hacklang site (with tutorial): hacklang.org

    View Slide