1. Pré-chargement

Une autre nouveauté de PHP 7.4 est la possibilité de pré-charger des classes, qui seront ensuite utilisables comme des classes natives du language, ou d'une extension.

  • Fichier de déclaration de la classe: preload-foo.inc
  • Fichier de test vérifiant l’existence de la classe: foo.php

Utilisation

$ php -dopcache.preload=preload-foo.inc foo.php
Class Remi\Foo exists

Nous utiliserons donc cette fonctionnalité avec FFI.

2. Compression ZSTD

Zstandard est un algorithme de compression très efficace et très répandu. La bibliothèque libzstd offre une implémentation de référence.

Il existe déjà une extension zstd pour PHP, que nous utiliserons aussi pour contrôler les performances de notre solution FFI.

  • Fichier de déclaration de la biblothèque, copié/collé/nettoyé depuis le fichier zstd.h de la bibliothèque: preload-zstd.h
  • Fichier de la classe Remi\Zstd qui pourra donc être préchargé: preload-zstd.inc
  • Fichier de test utilisant cette classe, ainsi que l'extension zstd pour comparaison: zstd.php

A noter: si la classe n'est pas pré-chargée, elle sera incluse par le script de test, utilisation simple :

$ php zstd.php

Si seul le script est préchargé, les entêtes seront chargées par un  appel à FFI;load(), utilisation :

$ php -d opcache.preload=preload-zstd.inc zstd.php

A partir de 7.4.0RC5 (ou avec les RPM de mon dépôt), il est aussi possible de précharger les entêtes qui seront récupérés avec FFI:scope(), utilisation:

$ php d ffi.preload=preload-zstd.h -d opcache.preload=preload-zstd.inc zstd.php

Dans les versions précédentes, le préchargement des entêtes ne fonctionnent qu'en utilisateur normal, et donc ne fonctionnement pas avec mod_php ou php-fpm qui est administrateur (root) lors de son lancement.

Exécution:

PHP version 7.4.0RC4
Use preloaded class
Using FFI::scope OK

Src length           = 8673632
ZSTD_compress        = 1828461
Src length           = 1828461
ZSTD_decompress      = 8673632
Check                = OK
Using FFI  extension = 0,09"

Src length           = 8673632
ZSTD_compress        = 1828461
Src length           = 1828461
ZSTD_decompress      = 8673632
Check                = OK
Using ZSTD extension = 0,09"

Pour l'utilisateur, le code utilisant FFI ou l'extension Zstd est équivalent, ainsi que les performances (aucune différence notable).

3. Client Redis

Il existe déjà plusieurs implémentation du client Redis en C ou en PHP, Cet exemple utilisera FFI pour accéder aux fonctions de la bibliothèque hiredis.

  • Fichier de déclaration de la biblothèque, copié/collé/nettoyé depuis les fichiers hiredis/hredis.h et hiredis/read.h de la bibliothèque: preload-redis.h
  • Fichier de la classe Remi\Redis qui pourra donc être préchargé: preload-redis.inc
  • Fichier de test utilisant cette classe: redis.php

Utilisation (extrait) :

$ php74 -d ffi.preload=preload-redis.h -d opcache.preload=preload-redis.inc redis.php
...
+ Remi\Redis::__construct(localhost, 6379)
+ Remi\Redis::initFFI()
+ Remi\Redis::del(foo)
int(1)
+ Remi\Redis::get(foo)
NULL
+ Remi\Redis::set(foo, 2019/10/23 12:45:03)
string(2) "OK"
+ Remi\Redis::get(foo)
string(19) "2019/10/23 12:45:03"
+ Remi\Redis::__destruct

Ce code simplissime, écrit en quelques heures fonctionne est rempli sa mission.

4. Liens

  • Documentation complète et très détaillée : https://www.php.net/ffi
  • Projet FFIme d'Anthony Ferrara permettant d'automatiser une partie du travail (expérimental)
  • Dépôt git des examples utilisés

5. Conclusion

FFI apparait comme un nouveau moyen de développement, directement en PHP, et permettant plus de fonctionnalités, sans devoir recourir à la création et la maintenance d'extension écrite en langage C.

Son utilisation nécessite tout de même de solides connaissances en C, pour comprendre les entêtes et la documentation des bibliothèques et pour éviter les fuites de mémoire, mais devrait attirer plus de développeurs / contributeurs.

L'avenir nous dira si elle tient ses promesses pour une utilisation en production, et si elle permettra de diminuer le nombres d'extensions existantes et qui devront être  maintenues et adaptées pour les prochaines versions de PHP.