Utilisation de l'extension FFI avec PHP 7.4
L'extension FFI (Foreign Function Interface) permet d'accéder aux fonctionnalités de bibliothèques systèmes directement depuis PHP sans recours à une autre extension.
Voici quelques exemples, résultats de mes tests de cette extension.
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.