HHVM

et Hack

Pascal MARTIN, http://blog.pascal-martin.fr / pmartin@php.net / @pascal_martin

Appuyez sur [s] pour ouvrir les notes présentateur dans une nouvelle fenêtre.

Un peu
d'histoire

Facebook

  • Forte fréquentation
  • Performances ?
  • PHP

HipHop — HPHP

  • 2009
  • Compilation PHP → C++ → Exécutable
  • Interpréteur (env. de dév.)
  • Mais…
    • Compilation longue, perte de souplesse
    • Production ≠ Développement, 2 projets à maintenir

HHVM

  • Mars 2013
  • Language : PHP
  • Compilation Just In Time
  • Serveur web intégré

HHVM + Hack

  • Mars 2014
  • Languages : PHP et Hack
  • FastCGI

HHVM

HHVM

  • Compilation JIT
  • FastCGI (derrière nginx / Apache)
  • hhvm.com

Installation

  • Cycle de releases
    • Internes : toutes les 2 semaines
    • Externes : toutes les 8 semaines
    • Nightly
  • Paquets pour les distributions les + utilisées
    • Ubuntu 10/12/14.04, Debian 7/8, Mint
    • Fedora 20, CentOS 6.x
  • Compilation depuis les sources
  • Développement / test nightly : vicb/hhvm-vagrant

Stack standard

  • Apache / nginx
  • HHVM en FastCGI
    • Comme php-fpm
  • Base de données, stockage, …

Utilisation et compatibilité

  • HHVM et site simple
  • Exécutable hhvm en CLI
  • Compatibilité Logiciels et Frameworks
    • Composer, Doctrine2, guzzle, monolog, twig : 100%
    • zf2, symfony, laravel : 97-100%
    • phpbb3, phpMyAdmin, mediawiki : 100%

Extensibilité

  • Extension PHP intégrées : curl, dom, json, ldap, memcached, mysql, pdo, phar, soap, spl, …
  • Extensions externes : geoip, mongo, pgsql, …
  • Code PHP intégré à HHVM après re-compilation
  • Extensions écrites en C++

Performances

  • Faites le test sur vos applications !

Hack

Hack ?

Mais pourquoi ?

  • Ajout de fonctionnalités
  • Qualité ↗
  • Risque d'erreurs ↘
  • Compatibilité avec PHP

Coder en Hack

  • Balise <?hh en début de fichier
  • Éventuellement : extension .hh
  • Marqueur ?> non supporté !
  • Pas de mélange Hack/HTML !

<?hh
    echo "Hello, Hack !";

                    

Typage

  • Type de retour fonctions / méthodes
  • Type pour les variables membres
  • Types nullables
  • Collections type-safe
  • Outil de vérification de types
  • Détection avant l'exécution, code + explicite

Types de retour

Fonctions, Méthodes


<?hh
function ma_fonction() : int {
    return "une chaine";
}

var_dump(ma_fonction());
                    

Fatal error: Value returned from ma_fonction()
    must be of type int, 
    string given in /…/types-01.php on line 4
                    

Typage de paramètres

Étendu aux types scalaires


<?hh
class MaClasse {
    public static function test(string $str, int $entier) {
        return sprintf("%s, %d", $str, $entier);
    }
}

var_dump(MaClasse::test("Hello", 42));
                    

Types nullable

  • Valeur doit être du type spécifié,
  • ou null
  • A n'utiliser que quand c'est justifié

<?hh
function ma_fonction(string $str, ?int $a) {
    echo $str;
    if (null !== $a) {
        echo " " . $a;
    }
}

ma_fonction("Hello", null);
ma_fonction("Hello", 42);
                    

Quels types ?

  • Types primitifs : int, float, string, bool
  • Classes : MaClasse, Vector<type>, this
  • Mixed : mixed
  • Void : void

Quels types ?

  • Nullable : ?int
  • Tableaux : array, array<int>, array<MaClasse>, array<int, MaClasse>
  • Closures : function(string, int): bool
  • Tuples, éléments XHP, Generics et resource

Type Checker

  • Fichier .hhconfig à la racine du projet
  • Type checker fonctionne en arrière-plan
  • hh_client affiche son état

$ hh_client 
/…/types-01.php:4:12,23: Invalid return type
  /…/types-01.php:3:26,28: This is an int
  /…/types-01.php:4:12,23: It is incompatible with a string
                    

Generics

  • Type d'une classe est paramétré
  • Permet la vérification statique
  • Code lisible et explicite

<?hh
class MaClasse<T> {
    protected T $data;
    public function __construct(T $data) {
        $this->data = $data;
    }
    public function getData() : T {
        return $this->data;
    }
}

$a = new MaClasse("plop");
var_dump($a->getData());
                    

Generics

  • Classe ou méthode générique
  • MaClasse<string> et MaClasse<int> = deux types différents
  • Traits et interfaces peuvent être génériques
  • Contraintes
    • Type doit être un (sous-)type donné
    • class MaClasse<T as Iterator>

Collections

  • array de PHP : dictionnaires, ordre d'insertion conservé, clefs int/string, contenu de n'importe quel type
  • Collections de Hack : paramétrées (generics), spécifiques aux cas d'usages, objets
  • Vector, Map, Set, Pair
    • + version Immutable des 3 premières
  • Objectifs : code explicite, typage statique, performances

Collections : Vector


// Pas de 'new' !
$vector = Vector {10, 20};
$vector[] = 30;
$vector[] = 40;

// Accès direct avec [indice]
printf("\$vector[2] = %d\n", $vector[2]);

// Suppression d'un élément
$vector->removeKey(2);

// Itération avec foreach()
foreach ($vector as $key => $value) {
    printf("%d => %d\n", $key, $value);
}
                    

Collections

  • Map
    • Dictionnaire clef (int ou string) /valeur
    • Ordonné
  • Set
    • Stockage de valeurs (int ou string) uniques
    • Pas de clef !
  • ImmVector, ImmMap, ImmSet
  • Interfaces Const*

Et les array alors ?

  • Recommandation : Collections
  • array existent toujours
    • array
    • array<UnType>
    • array<int, UnType> et array<string, UnType>
    • array<T>, array<int, Tv>, array<string, Tv>
  • Doivent être typés en mode strict

Shapes

  • Notion de structure ou d'enregistrement
  • Avec type-checking
  • Assimilable à une classe n'ayant que des propriétés, publiques

<?hh
type Point = shape('x' => int, 'y' => int);

function display_point(Point $p) {
    printf("%d ; %d", $p['x'], $p['y']);
}

display_point( shape('x' => 10, 'y' => -2) );
                    

Tuple


<?hh
function ma_fonction(int $a, int $b) : (int, int) {
    return tuple($a*2, $b*2);
}

$result = ma_fonction(10, 20);
var_dump($result);
                    

array(2) {
  [0]=> int(20)
  [1]=> int(40)
}
                    

Lambda

  • PHP
    • Binding de variables non-automatique : use(...)
    • Syntaxe un peu verbeuse
  • Hack
    • Capture automatique
    • Syntaxe + courte
    • Opérateur ==>

Lambda


<?hh
$func = ($a, $b) ==> {
    return $a . " " . $b;
};
var_dump( $func("hello", "world") );

$result = array_map(
    $val ==> strtoupper($val),
    ["un", "deux", "trois", ]
);
var_dump($result);
                    

Lambda


<?hh
for ( $i = 1 ; $i < 5 ; $i++ ) {
    $func = $val ==> {
        // $i est automatiquement capturé
        return $i * $val;
    };
    var_dump(array_map(
        $func, 
        [10, 20, 30, 40, 50]
    ));
}
                    

Lambda

  • Type-hinting (parametres, retours) non supporté par le type-checker
  • Pas de valeurs par défaut
  • Pas de paramètre / retour par référence

Async

  • Parallélisation de tâches, en isolation
  • Exemple : I/O
  • Fonction asynchrone
  • Mots-clef : async et await

Async

Pas encore tout à fait évident

<?hh
async function helloAfter($name, $timeout) {
  // sleep asynchronously -- let other async functions do their job
  await SleepWaitHandle::create($timeout * 1000000);
  echo sprintf("hello %s\n", $name);
}

async function run() {
  $joe = helloAfter('Joe', 3);
  $mike = helloAfter('Mike', 1);
  // wait for both dependencies
  await GenArrayWaitHandle::create(array($joe, $mike));
}

run()->join();
                    

Async

  • Support basique pour l'instant
  • Travail en cours !
  • TODO : appels bases de données, gestion de mémoire, scheduling, …

Quatre modes

  • partial : par défaut
  • strict : tout doit être annoté, pas d'appel à du non-Hack, pas de code top-level
  • decl : permet des appels non-Hack
  • unsafe : désactive le type-checking

<?hh // strict
    // Ici, du code Hack (strict)
                    

Et encore ?

  • Annotation <<Override>>
  • Aliasing de types
  • XHP
  • Promotion des arguments du constructeur

<?hh
class Point {
    // $x et $y ne sont pas déclarés…
    public function __construct(
        protected int $x, 
        protected int $y
    ) {
        // … ni assignés
    }
}
                    

Non supporté

  • goto, syntaxe if: … endif;, and/or
  • Opérateur @
  • break N et continue N
  • Variables globales
  • Mélange HTML/Hack
  • Méthode du nom de la classe

PHP et Hack

En route vers…

Implémentation historique

  • Un langage, plusieurs publics
  • Performances ≠ besoin 1er de la majorité
  • Coût / risque de migration
    • PHP 5.3 : 51.8%
    • PHP 5.2 : 27.2%
    • PHP 5.4 : 17.3%
    • PHP 5.5 : 2.1%

Ouverture à la communauté

  • Fortement soutenu par une entreprise
  • Open-Source, volonté d'ouverture
    • PR Github
    • Compatibilité frameworks et logiciels
  • Bon accueil

Implémentations alternatives

Implémentations alternatives

  • Concurrence : faire avancer PHP
  • Risque de fractionnement
    • Evolution de chaque implémentation indépendamment des autres
    • Scripts / applis / bibliothèques ne fonctionnant que sous un moteur ou l'autre

PHPTour

23 et 24 juin 2014, Lyon

Questions ?

#AperoPHP

Présentation HHVM et Hack — AFUP Lyon, 27 mai 2014 — Pascal MARTIN, @pascal_martin